From 6ad17dc71bc398cf420f8055b7351d3cb092ff51 Mon Sep 17 00:00:00 2001 From: Marco Peters Date: Thu, 30 Jun 2022 13:40:11 +0200 Subject: [PATCH] moved idepix-aatsr to 8.x branch --- idepix-aatsr/.gitignore | 15 + idepix-aatsr/pom.xml | 95 +++ .../resource/aatsr_cloud_shadow_dev.py | 763 ++++++++++++++++++ .../esa/snap/idepix/aatsr/IdepixAatsrOp.java | 734 +++++++++++++++++ .../snap/idepix/aatsr/OrientationOpImage.java | 79 ++ .../idepix/aatsr/docs/aatsr/AatsrAlgo.html | 141 ++++ .../idepix/aatsr/docs/aatsr/AatsrIntro.html | 67 ++ .../aatsr/docs/aatsr/AatsrProcessor.html | 91 +++ .../docs/aatsr/images/Aatsr_IO-Params.png | Bin 0 -> 14193 bytes .../docs/aatsr/images/Aatsr_Proc-Params.png | Bin 0 -> 8335 bytes .../IlluminationPath_geometry1_small.png | Bin 0 -> 20151 bytes .../IlluminationPath_geometry2_small.png | Bin 0 -> 7473 bytes .../docs/aatsr/images/eq001_orientation.png | Bin 0 -> 3766 bytes .../docs/aatsr/images/eq002_apparentSza_1.png | Bin 0 -> 2804 bytes .../docs/aatsr/images/eq002_apparentSza_2.png | Bin 0 -> 711 bytes .../docs/aatsr/images/eq002_apparentSza_3.png | Bin 0 -> 1541 bytes .../docs/aatsr/images/eq003_searchPath_1.png | Bin 0 -> 8462 bytes .../docs/aatsr/images/eq003_searchPath_2.png | Bin 0 -> 7469 bytes .../docs/aatsr/images/eq003_searchPath_3.png | Bin 0 -> 3686 bytes .../docs/aatsr/images/eq003_searchPath_4.png | Bin 0 -> 6513 bytes .../docs/aatsr/images/eq003_searchPath_5.png | Bin 0 -> 3110 bytes .../docs/aatsr/images/eq003_searchPath_6.png | Bin 0 -> 2126 bytes .../docs/aatsr/images/eq003_searchPath_7.png | Bin 0 -> 2624 bytes .../org/esa/snap/idepix/aatsr/docs/help.hs | 24 + .../idepix/aatsr/docs/images/snap_header.jpg | Bin 0 -> 21069 bytes .../org/esa/snap/idepix/aatsr/docs/map.jhm | 12 + .../org/esa/snap/idepix/aatsr/docs/style.css | 181 +++++ .../org/esa/snap/idepix/aatsr/docs/toc.xml | 22 + idepix-aatsr/src/main/nbm/manifest.mf | 14 + .../org.esa.snap.core.gpf.OperatorSpi | 1 + idepix-aatsr/src/main/resources/helpset.xml | 7 + idepix-aatsr/src/main/resources/layer.xml | 44 + .../snap/idepix/aatsr/IdepixAatsrOpTest.java | 207 +++++ .../idepix/aatsr/OrientationOpImageTest.java | 67 ++ .../org/esa/snap/idepix/aatsr/RunOpMain.java | 52 ++ pom.xml | 2 + 36 files changed, 2618 insertions(+) create mode 100644 idepix-aatsr/.gitignore create mode 100644 idepix-aatsr/pom.xml create mode 100644 idepix-aatsr/resource/aatsr_cloud_shadow_dev.py create mode 100644 idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/IdepixAatsrOp.java create mode 100644 idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/OrientationOpImage.java create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrAlgo.html create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrIntro.html create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrProcessor.html create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/Aatsr_IO-Params.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/Aatsr_Proc-Params.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/IlluminationPath_geometry1_small.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/IlluminationPath_geometry2_small.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq001_orientation.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq002_apparentSza_1.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq002_apparentSza_2.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq002_apparentSza_3.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_1.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_2.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_3.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_4.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_5.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_6.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_7.png create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/help.hs create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/images/snap_header.jpg create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/map.jhm create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/style.css create mode 100644 idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/toc.xml create mode 100644 idepix-aatsr/src/main/nbm/manifest.mf create mode 100644 idepix-aatsr/src/main/resources/META-INF/services/org.esa.snap.core.gpf.OperatorSpi create mode 100644 idepix-aatsr/src/main/resources/helpset.xml create mode 100644 idepix-aatsr/src/main/resources/layer.xml create mode 100644 idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/IdepixAatsrOpTest.java create mode 100644 idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/OrientationOpImageTest.java create mode 100644 idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/RunOpMain.java diff --git a/idepix-aatsr/.gitignore b/idepix-aatsr/.gitignore new file mode 100644 index 00000000..eba1e305 --- /dev/null +++ b/idepix-aatsr/.gitignore @@ -0,0 +1,15 @@ +target/ +.idea +*.iml +Technical Note_cloudshadow_draft_v0.2.docx +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar diff --git a/idepix-aatsr/pom.xml b/idepix-aatsr/pom.xml new file mode 100644 index 00000000..c06fcfcb --- /dev/null +++ b/idepix-aatsr/pom.xml @@ -0,0 +1,95 @@ + + + + + 4.0.0 + + org.esa.snap + snap-idepix + 8.0.1 + + + idepix-aatsr + 8.0.3 + + nbm + + IdePix AATSR + Classification of pixels (cloud, cloud-shadow and land) originating from AATSR 4th reprocessing data. + + + 8.0.1 + 8.0.6 + + + + + org.esa.snap + idepix-core + ${idepix.version} + + + + org.esa.snap + ceres-core + + + org.esa.snap + ceres-jai + + + org.esa.snap + ceres-glayer + + + org.esa.snap + snap-core + + + org.esa.snap + snap-collocation + + + org.esa.snap + snap-gpf + + + + org.esa.s3tbx + s3tbx-sentinel3-reader + ${s3tbx.version} + + + + junit + junit + + + + + + + org.apache.netbeans.utilities + nbm-maven-plugin + + + + + + + diff --git a/idepix-aatsr/resource/aatsr_cloud_shadow_dev.py b/idepix-aatsr/resource/aatsr_cloud_shadow_dev.py new file mode 100644 index 00000000..6550edd9 --- /dev/null +++ b/idepix-aatsr/resource/aatsr_cloud_shadow_dev.py @@ -0,0 +1,763 @@ +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import sys +import os +import time +from scipy import interpolate +from scipy.signal import fftconvolve + +sys.path.append("C:\\Users\Dagmar\.snap\snap-python") +import snappy as snp +from snappy import Product +from snappy import ProductData +from snappy import ProductIO +from snappy import jpy +from snappy import PixelPos #org.esa.snap.core.datamodel.PixelPos + +GeoPos = jpy.get_type('org.esa.snap.core.datamodel.GeoPos') +PixelPos = jpy.get_type('org.esa.snap.core.datamodel.PixelPos') +GPF = jpy.get_type('org.esa.snap.core.gpf.GPF') +File = jpy.get_type('java.io.File') +ProgressMonitor = jpy.get_type('com.bc.ceres.core.ProgressMonitor') + +def getRefinedHeightFromCtp(ctp, slp, temperatures): #ctp: cloud top pressure, slp: sea level pressure, temperature-profile + height = 0.0 + prsLevels = np.array((1000., 950., 925., 900., 850., 800., 700., 600., 500., 400., 300., 250., 200., 150., 100., + 70., 50., 30., 20., 10., 7., 5., 3., 2., 1.)) + + if ctp >= prsLevels[-1]: + for i in range(len(prsLevels)- 1): + if ctp > prsLevels[0] or (ctp < prsLevels[i] and ctp > prsLevels[i + 1]): + t1 = temperatures[i] + t2 = temperatures[i + 1] + ts = (t2 - t1) / (prsLevels[i + 1] - prsLevels[i]) * (ctp - prsLevels[i]) + t1 + height = getHeightFromCtp(ctp, slp, ts) + break + + else: + # CTP < 1 hPa? This should never happen... + t1 = temperatures[-2] + t2 = temperatures[-1] + ts = (t2 - t1) / (prsLevels[-2] - prsLevels[-1]) * (ctp - prsLevels[-1]) + t1 + height = getHeightFromCtp(ctp, slp, ts) + + return height + +def getRefinedHeightFromBT(BT, slp, temperatures): #BT: brightness temperature, slp: sea level pressure, temperature-profile + #this function is not necessarily eindeutig! inversion in T(p) can lead to two (or more) solutions for p. + height1, height2, height1b, height2b = None, None, None, None + prsLevels = np.array((1000., 950., 925., 900., 850., 800., 700., 600., 500., 400., 300., 250., 200., 150., 100., + 70., 50., 30., 20., 10., 7., 5., 3., 2., 1.)) + + if BT >= np.min(temperatures) and BT <= np.max(temperatures): + for i in range(len(temperatures)- 1): + if BT > temperatures[i] and BT < temperatures[i + 1]: + ctp1 = prsLevels[i] + ctp2 = prsLevels[i + 1] + ctp = (ctp2 - ctp1) / (temperatures[i + 1] - temperatures[i]) * (BT - temperatures[i]) + ctp1 + height1 = getHeightFromCtp(ctp, slp, BT) + height1b = computeHeightFromPressure(ctp) + if BT < temperatures[i] and BT > temperatures[i + 1]: #inversion! + ctp1 = prsLevels[i] + ctp2 = prsLevels[i + 1] + ctp = (ctp2 - ctp1) / (temperatures[i + 1] - temperatures[i]) * (BT - temperatures[i]) + ctp1 + height2 = getHeightFromCtp(ctp, slp, BT) + height2b = computeHeightFromPressure(ctp) + + return height1, height2, height1b, height2b + +def getHeightFromCtp(ctp, p0, ts): + return -ts * (np.power(ctp / p0, 1. / 5.255) - 1) / 0.0065 + +def computeHeightFromPressure(pressure): + return -8000 * np.log(pressure / 1013.0) + +def investigate_AATSR4th_transect(plot_BT=False, plot_Temp=False): + path ="E:\Documents\projects\QA4EO\data\\transect\\" + # fname = "subset_0_of_ENV_AT_1_RBT____20021129T235200_20021130T013735_20210315T024827_6334_011_359______DSI_R_NT_004_TRANSECT.txt" + # todo: unfortunately, no radiance or BT is extracted! + fname = "subset_WATER_of_ENV_AT_1_RBT____20020810T083508_20020810T102042_20210303T040313_6334_008_264______DSI_R_NT_004_TRANSECT.txt" + # fname = "subset_LAND_of_ENV_AT_1_RBT____20020810T083508_20020810T102042_20210303T040313_6334_008_264______DSI_R_NT_004_TRANSECT.txt" + ##data from the snap-transect plot! Combine both for analysis. + fname_BT = "subset_WATER_S8_S9_of_ENV_AT_1_RBT____20020810T083508_TRANSECT.txt" + + d = pd.read_csv(path + fname, header=0, comment='#', sep='\t') + d_BT = pd.read_csv(path + fname_BT, header=0, comment='#', sep='\t') + print(d.shape) + print(d_BT.shape) + print(d.columns.values) + referencePressureLevels = np.array((1000., 950., 925., 900., 850., 800., 700., 600., 500., 400., 300., 250., 200., + 150., 100., 70., 50., 30., 20., 10., 7., 5., 3., 2., 1.)) + + col_BT = [a for a in d_BT.columns.values if 'BT' in a] + col_BT = [a for a in col_BT if not 'sigma' in a] + col_T = [a for a in d.columns.values if 'temperature_profile_tx_pressure' in a] + col_slp = [a for a in d.columns.values if 'surface_pressure' in a] + print(col_slp) + if plot_BT: + for v in col_BT: + plt.plot(d_BT[v].values, '-', label=v) + plt.legend() + plt.show() + + if plot_Temp: + ID = np.array(d_BT[col_BT[0]].values < 270) #todo: cloud flags? + print(np.sum(ID)) + d_BT = d_BT.loc[ID,:] + d_BT = d_BT.reset_index(drop=True) + d = d.loc[ID,:] + d = d.reset_index(drop=True) + number = np.random.random(10)*d.shape[0] + for i in number: + fig, ax = plt.subplots(1, 1, figsize=(5,5)) + ax.plot(d[col_T].loc[int(i),:].values, referencePressureLevels, '-') + for v in col_BT: + BT = d_BT[v].values[int(i)] + ax.plot((BT, BT), (np.min(referencePressureLevels), np.max(referencePressureLevels)), 'r-') + height1, height2, h1, h2 = getRefinedHeightFromBT(BT, d[col_slp].values[int(i)], d[col_T].loc[int(i),:].values) + print(i, BT, height1, height2, h1, h2) + ax.invert_yaxis() + ax.set_xlabel('Temperature T [K]') + ax.set_ylabel('pressure [hPa]') + fig.tight_layout() + plt.show() + +def get_band_or_tiePointGrid(product, name, dtype='float32', reshape=True, subset=None): + ## + # This function reads a band or tie-points, identified by its name , from SNAP product + # The fuction returns a numpy array of shape (height, width) + ## + if subset is None: + height = product.getSceneRasterHeight() + width = product.getSceneRasterWidth() + sline, eline, scol, ecol = 0, height-1, 0, width -1 + else: + sline,eline,scol,ecol = subset + height = eline - sline + 1 + width = ecol - scol + 1 + + var = np.zeros(width * height, dtype=dtype) + if name in list(product.getBandNames()): + product.getBand(name).readPixels(scol, sline, width, height, var) + elif name in list(product.getTiePointGridNames()): + var.shape = (height, width) + for i,iglob in enumerate(range(sline,eline+1)): + for j,jglob in enumerate(range(scol,ecol+1)): + var[i, j] = product.getTiePointGrid(name).getPixelDouble(jglob, iglob) + var.shape = (height*width) + else: + raise Exception('{}: neither a band nor a tie point grid'.format(name)) + + if reshape: + var.shape = (height, width) + + return var + +def set_cloud_mask_from_Bayesian(cloudB): + single_moderate_mask = np.bitwise_and(cloudB, 2 ** 1) == 2 ** 1 + no_bayes_available_mask = np.bitwise_and(cloudB, 2 ** 7) == 2 ** 7 + out = np.zeros(cloudB.shape) + np.nan + if np.sum(no_bayes_available_mask)==0: + out = single_moderate_mask + return out + + +def set_cloud_mask_from_Confidence(cloudB): + summary_cloud_mask = np.bitwise_and(cloudB, 2 ** 14) == 2 ** 14 + return summary_cloud_mask + + +def set_cloud_mask_from_cloudBand(cloudB): + visible_mask = np.bitwise_and(cloudB, 2 ** 0) == 2 ** 0 + gross_cloud_mask = np.bitwise_and(cloudB, 2 ** 7) == 2 ** 7 + thin_cirrus_mask = np.bitwise_and(cloudB, 2 ** 8) == 2 ** 8 + medium_high_mask = np.bitwise_and(cloudB, 2 ** 9) == 2 ** 9 + return np.array(visible_mask + gross_cloud_mask + thin_cirrus_mask + medium_high_mask > 0) + +def set_land_mask(product, subset=None): + confid_in = get_band_or_tiePointGrid(product, 'confidence_in', 'int32', subset=subset) + #LAND : coastline, tidal, land, inland_water + coastline_mask = np.bitwise_and(confid_in, 2 ** 0) == 2 ** 0 + tidal_mask = np.bitwise_and(confid_in, 2 ** 2) == 2 ** 2 + land_mask = np.bitwise_and(confid_in, 2 ** 3) == 2 ** 3 + inland_water_mask = np.bitwise_and(confid_in, 2 ** 4) == 2 ** 4 + return np.array(coastline_mask + tidal_mask + land_mask + inland_water_mask > 0) + +def calculate_view_azimuth_interpolation_singleline( vaa_line, width, plot=False): + + nx0 = 0 + nx1 = 200 + nx2 = 340 + nx3 = width + nx_change = 272 # nadir line between 271 + 272 + + vaa_out = np.copy(vaa_line) + + ## + # interpolation for row ny: + y1 = vaa_line[nx0:nx1] + y2 = vaa_line[nx2:] + x1 = np.arange(nx0, nx1, 1.) + x2 = np.arange(nx2, nx3, 1.) + + p = np.polyfit(x1, y1, 2) + print(p) + delta = vaa_line[nx1] - (p[0] * (nx1) ** 2 + p[1] * nx1 + p[2]) + print(vaa_line[nx1]) + print(p[0] * (nx1) ** 2 + p[1] * nx1 + p[2]) + x_out = np.arange(nx1, nx_change, 1.) + y_out1 = p[0] * (x_out) ** 2 + p[1] * x_out + p[2] + delta + vaa_out[nx1:nx_change] = y_out1 + + p = np.polyfit(x2, y2, 2) + delta = vaa_line[nx2] - (p[0] * (nx2) ** 2 + p[1] * nx2 + p[2]) + x_out = np.arange(nx_change, nx2, 1.) + y_out2 = p[0] * (x_out) ** 2 + p[1] * x_out + p[2] + delta + + vaa_out[nx_change:nx2] = y_out2 + + print(vaa_out[(nx_change-1):(nx_change+1)]) + if plot: + plt.plot(vaa_line, '-', label='from TPG') + plt.plot(vaa_out, 'r-', label='Interpolation') + plt.xlabel('Pixel X') + plt.ylabel('View Azimuth Angle') + plt.legend() + plt.show() + + return vaa_out + + +def calculate_view_zenith_interpolation_singleline_OLCI(vza, ny): + + nx0 = 3500 + nx1 = 3580 + nx2 = 3649 + nx3 = nx2 + 80 + nx_change = 3616 + + vza_out = np.copy(vza) + + ## + # interpolation for row ny: + + y1 = vza[ny, nx0:nx1] + y2 = vza[ny, nx2:nx3] + x1 = np.arange(nx0, nx1, 1.) + x2 = np.arange(nx2, nx3, 1.) + + + p = np.polyfit(x1, y1, 2) + x_out = np.arange(nx1, nx_change, 1.) + y_out1 = p[0] * (x_out) ** 2 + p[1] * x_out + p[2] + vza_out[ny, nx1:nx_change] = y_out1 + + p = np.polyfit(x2, y2, 2) + x_out = np.arange(nx_change, nx2, 1.) + y_out2 = p[0] * (x_out) ** 2 + p[1] * x_out + p[2] + + vza_out[ny, nx_change:nx2] = y_out2 + + return vza_out + +def setRelativePathIndex_and_TheoreticalHeight(sza, saa, oza, x_tx, orientation, spatialResolution, maxObjectAltitude, minSurfaceAltitude): #oaa replaced by x_tx + shadow_angle_PixelCoord = (saa - orientation) + 180. + cosSaa = np.cos(shadow_angle_PixelCoord*np.pi/180. - np.pi / 2.) + sinSaa = np.sin(shadow_angle_PixelCoord*np.pi/180. - np.pi / 2.) + + #modified sza for influence of oza: + if saa - orientation < 180.: + if x_tx < 0: + sza = np.arctan(np.tan(sza * np.pi / 180.) - np.tan(oza * np.pi / 180.)) * 180. / np.pi #negative?? + else: + sza = np.arctan(np.tan(sza * np.pi / 180.) + np.tan(oza * np.pi / 180.)) * 180. / np.pi + else: + if x_tx < 0: + sza = np.arctan(np.tan(sza * np.pi / 180.) + np.tan(oza * np.pi / 180.)) * 180. / np.pi #negative + else: + sza = np.arctan(np.tan(sza * np.pi / 180.) - np.tan(oza * np.pi / 180.)) * 180. / np.pi #positive + + + deltaProjX = ((maxObjectAltitude - minSurfaceAltitude) * np.tan(sza*np.pi/180.) * cosSaa) / spatialResolution + deltaProjY = ((maxObjectAltitude - minSurfaceAltitude) * np.tan(sza*np.pi/180.) * sinSaa) / spatialResolution + + x0 = 0 + y0 = 0 + + x1 = x0 + deltaProjX + np.sign(deltaProjX) * 1.5 + y1 = y0 + deltaProjY + np.sign(deltaProjY) * 1.5 + + #create index steps + # Path touches which pixels? + #setup all pixel centers from x0/y0 to x1/y1. + # calculate distance between pixel center and line (X0, X1) + # all distances below/equal sqrt(2*0.5^2): the pixel is touched by the line and a potential shadow pixel. + + if x0 0) > 0: + eline = np.arange(0, height-1, 1)[diffSZATest>0] + eline = eline[eline > sline] + eline = np.min(eline) + else: + eline = height + sline = int(sline) + eline = int(eline) + # eline = np.max(np.arange(0, height, 1)[SZATest]) + sza = sza[sline:eline,:] + subset = (int(sline), int(eline-1), 0, width-1) + saa = get_band_or_tiePointGrid(product, 'solar_azimuth_tn', subset=subset) + oza = get_band_or_tiePointGrid(product, 'sat_zenith_tn', subset=subset) + x_tx = get_band_or_tiePointGrid(product, 'x_tx', subset=subset) # at nadir line x_tx changes sign. x<272 : x_tx<0; x>=272 : x_tx >0 + + ## OAA is not needed! use fixed position of nadir line between x = 271, 272 + # oaa = get_band_or_tiePointGrid(product, 'sat_azimuth_tn') #needs adjustment! + # test sat azimuth interpolation. + # a = calculate_view_azimuth_interpolation_singleline(oaa[0,:], width, plot=True) + # oaa_correct = np.zeros((height, width)) + # for i in range(height): + # oaa_correct[i,:] = a + + + ## derive orientation at coarse raster positions. + ## interpolate/extrapolate spatially to entire grid + GridStep = 100 + X, Y = np.mgrid[1:(width-1):GridStep, 1:(eline-sline-1):GridStep] + print("start Position") + orientationS = np.zeros(X.shape) + for iy in range(orientationS.shape[0]): + for ix in range(orientationS.shape[1]): + x = X[iy, ix] + y = Y[iy, ix] + pixelPos1 = PixelPos(x-1 + 0.5, sline + y + 0.5) + geoPos = product.getSceneGeoCoding().getGeoPos(pixelPos1, None) + lat1 = geoPos.getLat() + lon1 = geoPos.getLon() + pixelPos2 = PixelPos(x + 1 + 0.5, sline + y + 0.5) + geoPos = product.getSceneGeoCoding().getGeoPos(pixelPos2, None) + lat2 = geoPos.getLat() + lon2 = geoPos.getLon() + orientationS[iy, ix] = calculate_orientation(lat1, lon1, lat2, lon2) * 180. / np.pi + + f = interpolate.RectBivariateSpline(y=np.arange(1,(eline-sline-1), GridStep), x=np.arange(1, (width-1), GridStep), + z=orientationS, bbox=[0, width, 0, (eline-sline)] , kx=3, ky=3, s=0) + xx = np.arange(0, width, 1) + yy = np.arange(0, (eline-sline), 1) + orientation = np.transpose(f(xx, yy)) # orientationFull, + + ### by Pixel: Lat, Lon, Orientation + # deriving North direction on pixel grid, orientation + # lat = np.zeros((eline - sline , width)) + # lon = np.zeros((eline - sline , width)) + # print("start Position") + # for ix, x in enumerate(range(0, width)): + # for iy, y in enumerate(range(sline, eline)): + # pixelPos = PixelPos(x + 0.5, y + 0.5) + # geoPos = product.getSceneGeoCoding().getGeoPos(pixelPos, None) + # lat[iy, ix] = geoPos.getLat() + # lon[iy, ix] = geoPos.getLon() + # + # #direction of North on the grid. Used to adjust the sun azimuth angle to grid directions. + # #in degree! + # print("start orientation") + # orientation = np.zeros(lat.shape) + # for i in range(orientation.shape[0]): + # for j in range(width - 2): + # orientation[i, j + 1] = calculate_orientation(lat[i, j], lon[i, j], lat[i, j + 2], lon[i, j + 2]) * 180./np.pi + # orientation[:, 0] = orientation[:, 1] + # orientation[:, width-1] = orientation[:, width-2] + + ### plot orientation comparison + # fig, ax = plt.subplots(1, 2, figsize=(8,5)) + # im = ax[0].imshow(orientationFull) + # fig.colorbar(im, ax=ax[0], shrink=0.5) + # ax[0].set_title('orient. Interpolated') + # im=ax[1].imshow(orientation) + # fig.colorbar(im, ax=ax[1], shrink=0.5) + # ax[1].set_title('all pixl orientation') + # plt.show() + # + # fig,ax = plt.subplots(1, 2, figsize=(8,5)) + # im = ax[0].imshow((orientationFull- orientation)/orientation*100.) + # fig.colorbar(im, ax=ax[0], shrink=0.5) + # ax[0].set_title('rel.Diff orient. Interpolated %') + # im = ax[1].plot(orientation[:, 1], 'r-', label='all') + # im = ax[1].plot(orientationFull[:, 1], 'b--', label='interpol.') + # im = ax[1].plot( Y[0,:], orientationS[0, :], 'k+', label='points') + # ax[1].legend() + # plt.show() + fig,ax = plt.subplots(1, 2, figsize=(8,5)) + im = ax[0].imshow(orientation) + fig.colorbar(im, ax=ax[0], shrink=0.5) + ax[0].set_title('orient. Interpolated ') + im = ax[1].plot(orientation[:, 1], 'r-', label='all') + im = ax[1].plot(Y[0,:], orientationS[0, :], 'k+', label='points') + ax[1].legend() + plt.show() + + ### cloud mask + + if cloudflagType == 'new': + bayes_in = get_band_or_tiePointGrid(product, 'bayes_in', 'int32', subset=subset) + bayesMask = set_cloud_mask_from_Bayesian(bayes_in) + + confid_in = get_band_or_tiePointGrid(product, 'confidence_in', 'int32', subset=subset) + confidMask = set_cloud_mask_from_Confidence(confid_in) + + if np.sum(np.isnan(bayesMask)) > 0: + cloudMask = confidMask + else: + #todo: what to do with partial information in bayesian cloud mask? + print('cloud mask to be done') + cloudMask = np.logical_or(bayesMask, confidMask) + + else: + cloud_in = get_band_or_tiePointGrid(product, 'cloud_in', 'int32', subset=subset) + cloudMask = set_cloud_mask_from_cloudBand(cloud_in) + + ## landmask + landMask = set_land_mask(product, subset=subset) + + ### convolution cloudmask and search radius, convolution landmask and search radius + # every 1000 or 2000 pixels (y-direction), the convolution is done with the current, mean search radius defined by SZA and CTH. + + ConvolStep = 2000 + upperLimits = np.arange(0, cloudMask.shape[0], ConvolStep) + if len(upperLimits)> 1: + upperLimits[-1] = cloudMask.shape[0] + else: + upperLimits = np.array((0, cloudMask.shape[0])) + + startSearchMask = np.zeros((cloudMask.shape)) + landConvolveMask = np.zeros((landMask.shape)) + for i, up in enumerate(upperLimits[1:]): + #setup kernel + radius = cth * np.tan(np.median(sza[upperLimits[i]:up,:])*np.pi/180.) + print(i, radius) + kernel = setup_round_kernel(radius=radius, spacing=(1000.,1000.)) #todo: use an elongated shape in direction of illumination! + # kNy, kNx = kernel.shape + # convolveMatrixSubset = cloudMask[upperLimits[i]:up,:] + # convolveMatrix = np.zeros((convolveMatrixSubset.shape[0]+2*kernel.shape[0], convolveMatrixSubset.shape[1]+2*kernel.shape[1])) + # convolveMatrix[kNy:(-kNy), kNx:(-kNx)] = convolveMatrixSubset + # for iy in range(kNy): + # convolveMatrix[iy,kNx:(-kNx)] = convolveMatrixSubset[0,:] + # convolveMatrix[-(iy+1), kNx:(-kNx)] = convolveMatrixSubset[-1,:] + # for ix in range(kNx): + # convolveMatrix[:, ix] = convolveMatrix[:, kNx] + # convolveMatrix[:, -(ix + 1)] = convolveMatrix[:, -(kNx+1)] + # + # perc_circle = fftconvolve(convolveMatrix, kernel, mode='same') + startSearchMask[upperLimits[i]:up, :] = convolve_mask_kernel(cloudMask[upperLimits[i]:up, :], kernel) + landConvolveMask[upperLimits[i]:up, :] = convolve_mask_kernel(landMask[upperLimits[i]:up, :], kernel) + + startSearchMask = np.logical_and(startSearchMask >0.001, startSearchMask < 0.998) + startSearchMask = np.logical_and(startSearchMask, landConvolveMask > 0.001) + print(np.sum(startSearchMask), np.sum(cloudMask)) + print(np.sum(np.logical_and(startSearchMask, cloudMask==1))) + + fig, ax = plt.subplots(1, 2, figsize=(5, 8)) + ax[0].imshow(cloudMask) + ax[0].set_title('AATSR cloud mask') + ax[1].imshow(startSearchMask) + ax[1].set_title('Start Points') + plt.show() + + elevation = get_band_or_tiePointGrid(product, 'elevation_in', subset=subset) + spatialResolution = 1000. # todo: read from product + # maxObjectAltitude = np.nanmax(elevation) + minSurfaceAltitude = np.nanmin(elevation) + ShadowArray = np.zeros(elevation.shape) + + ### + # print(filename) + # print('SZA', sza[yline, :]) + # print('orientation', orientation[yline, :]) + # print('minSurfaceAltitude', minSurfaceAltitude) + # print('startSearchMask', startSearchMask[yline, :]) + + this_height = sza.shape[0] + this_width = sza.shape[1] + count = 0 + startTime = time.time() + for i in range(this_height): + for j in range(this_width): + if cloudMask[i, j]==1 and startSearchMask[i, j]: + count += 1 + if count % 10000 == 0: + print(count) + #search for cloud shadow. + # calculate theoretical height at search path position. + illuPathSteps, illuPathHeight, threshHeight = setRelativePathIndex_and_TheoreticalHeight(sza=sza[i, j], saa=saa[i, j], + oza=oza[i, j], x_tx = x_tx[i, j],#oaa = oaa_correct[i, j], + orientation = orientation[i, j], + spatialResolution=spatialResolution, + maxObjectAltitude=cth, + minSurfaceAltitude=minSurfaceAltitude) + X = np.sqrt(illuPathSteps[:, 0] ** 2 + illuPathSteps[:, 1] ** 2) + + IndexArray = np.copy(illuPathSteps) + IndexArray[:, 0] += j + IndexArray[:, 1] += i + # find cloud free positions along the search path: + ID = np.logical_and(np.logical_and(IndexArray[:, 0] >= 0, IndexArray[:, 0] < this_width), + np.logical_and(IndexArray[:, 1] >= 0, IndexArray[:, 1] < this_height)) + + if np.sum(ID) > 3: # path positions + IndexArray = IndexArray[ID, :] + BaseHeightArray = illuPathHeight[ID] + # Xx = X[ID] + elevPath = elevation[IndexArray[:, 1], IndexArray[:, 0]] + + # plt.plot(Xx, elevPath, 'g+') + # plt.plot(Xx, BaseHeightArray, 'rx') + # plt.show() + ID2 = np.logical_and(np.abs(BaseHeightArray - elevPath) < threshHeight , + np.logical_not(cloudMask[IndexArray[:, 1], IndexArray[:, 0]])) + + ShadowArray[IndexArray[ID2, 1], IndexArray[ID2, 0]] = 1 + + # plt.imshow(ShadowArray) + # plt.show() + # + # out = cloudMask + ShadowArray *2 + # plt.imshow(out) + # plt.show() + endTime = time.time() + + print("Time", startTime, endTime) + + outpath = scene_path + filename[:42] + "_testCloudShadow_Cloud_" +cloudflagType+ ".dim" + outProduct = Product('AASTR_cloudShadow', 'AASTR_cloudShadow', width, this_height) #height + outProduct.setFileLocation(File(outpath)) + + ProductSubsetDef = jpy.get_type('org.esa.snap.core.dataio.ProductSubsetDef') + subset_def = ProductSubsetDef() + subset_def.setRegion(0, sline, width, eline) # (0,0,width, height) + product.transferGeoCodingTo(outProduct, subset_def) + + rad = get_band_or_tiePointGrid(product, 'S2_radiance_in', subset=subset) + band = outProduct.addBand("S2_radiance_in", ProductData.TYPE_FLOAT32) + band.setNoDataValue(np.nan) + band.setNoDataValueUsed(True) + sourceData = rad.reshape(cloudMask.shape).astype('float32') + band.setRasterData(ProductData.createInstance(sourceData)) + + band = outProduct.addBand("cloudMask", ProductData.TYPE_INT16) + band.setNoDataValue(np.nan) + band.setNoDataValueUsed(True) + sourceData = cloudMask.reshape(cloudMask.shape).astype('int16') + band.setRasterData(ProductData.createInstance(sourceData)) + + band = outProduct.addBand("shadowMask", ProductData.TYPE_INT16) + band.setNoDataValue(np.nan) + band.setNoDataValueUsed(True) + sourceData = ShadowArray.reshape(cloudMask.shape).astype('int16') + band.setRasterData(ProductData.createInstance(sourceData)) + + ProductIO.writeProduct(outProduct, outpath, 'BEAM-DIMAP') + + product.closeIO() + outProduct.closeIO() + + +def analyse_AATSR4th_transect(varname='sat_azimuth_tn', start = 10950, end = 12950, step=50): + scene_path = "E:\Documents\projects\QA4EO\AATSR4th\\" + filename = "ENV_AT_1_RBT____20020810T083508_20020810T102042_20210303T040313_6334_008_264______DSI_R_NT_004.dim" + # filename = "subset_0_of_ENV_AT_1_RBT____20020810T083508_20020810T102042_20210303T040313_6334_008_264______DSI_R_NT_004.dim" + # filename = "subset_SouthernHem_of_ENV_AT_1_RBT____20021129T235200_20021130T013735_20210315T024827_6334_011_359______DSI_R_NT_004.dim" + # filename = "subset_LowSunNorth_of_ENV_AT_1_RBT____20020810T083508_20020810T102042_20210303T040313_6334_008_264______DSI_R_NT_004.dim" + product = snp.ProductIO.readProduct(os.path.join(scene_path, filename)) + height = product.getSceneRasterHeight() + width = product.getSceneRasterWidth() + + # sza = get_band_or_tiePointGrid(product, 'solar_zenith_tn') # sline,eline,scol,ecol = subset + subset = (start, end, 0, width - 1) + vaa = get_band_or_tiePointGrid(product, varname, subset=subset) + + + yList = np.arange(start, end, step, dtype='int16') + latPart = np.zeros((len(yList), width)) + lonPart = np.zeros((len(yList), width)) + orientationPart = np.zeros((len(yList), width)) + + for j, y in enumerate(yList): + for ix, x in enumerate(range(0, width)): + pixelPos = PixelPos(x + 0.5, y + 0.5) + geoPos = product.getSceneGeoCoding().getGeoPos(pixelPos, None) + latPart[j, ix] = geoPos.getLat() + lonPart[j, ix] = geoPos.getLon() + + for i in range(orientationPart.shape[0]): + for j in range(width - 2): + orientationPart[i, j + 1] = calculate_orientation(latPart[i, j], lonPart[i, j], latPart[i, j + 2], + lonPart[i, j + 2]) * 180. / np.pi + orientationPart[:, 0] = orientationPart[:, 1] + orientationPart[:, width - 1] = orientationPart[:, width - 2] + + fig, ax = plt.subplots(1, 2, figsize=(8,5)) + for j,y in enumerate(yList): + ax[0].plot(vaa[y-start, :], '-', label=y) + ax[1].plot(vaa[y-start, :]-orientationPart[j,:], '-', label=y) + ax[0].set_xlabel('pixel No X') + ax[0].set_ylabel('view azimuth angle') + ax[1].set_xlabel('pixel No X') + ax[1].set_ylabel('view azimuth angle - orientation') + plt.show() + + # yList = np.arange(end, end+2000, 50, dtype='int16') + # for y in yList: + # plt.plot(vaa[y,:], '-', label=y) + # plt.legend() + # plt.show() + + +# investigate_AATSR4th_transect(plot_BT=True) +# investigate_AATSR4th_transect(plot_Temp=True) + +### cloud shadow processor +cloud_shadow_processor_AASTR(cloudflagType='old') + +# analyse_AATSR4th_transect() +# analyse_AATSR4th_transect(start=11600, end=30860, step=1000) \ No newline at end of file diff --git a/idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/IdepixAatsrOp.java b/idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/IdepixAatsrOp.java new file mode 100644 index 00000000..b7f382af --- /dev/null +++ b/idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/IdepixAatsrOp.java @@ -0,0 +1,734 @@ +/* + * Copyright (C) 2022 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see http://www.gnu.org/licenses/ + */ +package org.esa.snap.idepix.aatsr; + +import com.bc.ceres.core.ProgressMonitor; +import com.bc.ceres.core.SubProgressMonitor; +import org.esa.snap.core.dataio.geocoding.ComponentGeoCoding; +import org.esa.snap.core.datamodel.Band; +import org.esa.snap.core.datamodel.FlagCoding; +import org.esa.snap.core.datamodel.GeoCoding; +import org.esa.snap.core.datamodel.Mask; +import org.esa.snap.core.datamodel.Product; +import org.esa.snap.core.datamodel.ProductData; +import org.esa.snap.core.datamodel.RasterDataNode; +import org.esa.snap.core.gpf.Operator; +import org.esa.snap.core.gpf.OperatorException; +import org.esa.snap.core.gpf.OperatorSpi; +import org.esa.snap.core.gpf.Tile; +import org.esa.snap.core.gpf.annotations.OperatorMetadata; +import org.esa.snap.core.gpf.annotations.Parameter; +import org.esa.snap.core.gpf.annotations.SourceProduct; +import org.esa.snap.core.gpf.annotations.TargetProduct; +import org.esa.snap.core.image.ImageManager; +import org.esa.snap.core.util.BitSetter; +import org.esa.snap.core.util.ImageUtils; +import org.esa.snap.core.util.ProductUtils; +import org.esa.snap.core.util.SystemUtils; +import org.esa.snap.core.util.math.MathUtils; +import org.esa.snap.idepix.core.IdepixConstants; +import org.esa.snap.idepix.core.IdepixFlagCoding; + +import javax.imageio.ImageIO; +import javax.media.jai.BorderExtender; +import javax.media.jai.ImageLayout; +import javax.media.jai.Interpolation; +import javax.media.jai.JAI; +import javax.media.jai.KernelJAI; +import javax.media.jai.OpImage; +import javax.media.jai.RenderedOp; +import javax.media.jai.operator.ClampDescriptor; +import javax.media.jai.operator.ConvolveDescriptor; +import javax.media.jai.operator.CropDescriptor; +import javax.media.jai.operator.DivideByConstDescriptor; +import javax.media.jai.operator.ExtremaDescriptor; +import javax.media.jai.operator.FormatDescriptor; +import javax.media.jai.operator.MosaicDescriptor; +import javax.media.jai.operator.MultiplyConstDescriptor; +import javax.media.jai.operator.ScaleDescriptor; +import javax.media.jai.operator.SubtractConstDescriptor; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.logging.Level; +import java.util.stream.IntStream; + +/** + * The IdePix pixel classification operator for AATSR products (4th repro). + */ +@OperatorMetadata(alias = "Idepix.Aatsr", + category = "Optical/Preprocessing/Masking", + version = "1.0", + authors = "Dagmar Mueller, Marco Peters", + copyright = "(c) 2022 by Brockmann Consult", + description = "Pixel identification and classification for AATSR 4th repro data.") +public class IdepixAatsrOp extends Operator { + + private static final boolean DEBUG = false; + private final static int SPATIAL_RESOLUTION = 1000; // in meter // better to get it from product + + @SourceProduct(label = "AATSR L1b product", + description = "The AATSR L1b source product.") + private Product sourceProduct; + + @TargetProduct(description = "The target product.") + private Product targetProduct; + + @Parameter(label = "Copy source bands", defaultValue = "false") + private boolean copySourceBands; + + @Parameter(label = "Assumed cloud top height", defaultValue = "6000") + private int cloudTopHeight; + private Mask startSearchMask; + private Rectangle dayTimeROI; + private RenderedOp orientationImage; + private double minSurfaceAltitude; + private int maxShadowDistance; + private Band idepixFlagBand; + + // overall parameters + + @Override + public void initialize() throws OperatorException { + // 1) + validate(sourceProduct); + + // 2) create TargetProduct + final String targetProductName = sourceProduct.getName() + "_idepix"; + targetProduct = createCompatibleProduct(sourceProduct, targetProductName); + + // init ComponentGeoCoding is necessary for SNAP8.x, can be removed for SNAP9 + final GeoCoding sceneGeoCoding = sourceProduct.getSceneGeoCoding(); + if (sceneGeoCoding instanceof ComponentGeoCoding) { + ComponentGeoCoding compGC = (ComponentGeoCoding) sceneGeoCoding; + compGC.initialize(); + } + + if (copySourceBands) { + ProductUtils.copyProductNodes(sourceProduct, targetProduct); + for (Band band : sourceProduct.getBands()) { + if (!targetProduct.containsBand(band.getName())) { + ProductUtils.copyBand(band.getName(), sourceProduct, targetProduct, true); + } + } + } else { + ProductUtils.copyGeoCoding(sourceProduct, targetProduct); + targetProduct.setStartTime(sourceProduct.getStartTime()); + targetProduct.setEndTime(sourceProduct.getEndTime()); + } + + // 2.1) copy source bands (todo - which source bands to include?) + // 2.2) create flag band compatible with other IdePix processors but only + idepixFlagBand = targetProduct.addBand(IdepixConstants.CLASSIF_BAND_NAME, ProductData.TYPE_INT16); + FlagCoding flagCoding = IdepixFlagCoding.createDefaultFlagCoding(IdepixConstants.CLASSIF_BAND_NAME); + targetProduct.getFlagCodingGroup().add(flagCoding); + idepixFlagBand.setSampleCoding(flagCoding); + IdepixFlagCoding.setupDefaultClassifBitmask(targetProduct); + } + + @Override + public void doExecute(ProgressMonitor pm) throws OperatorException { + pm.beginTask("Executing cloud shadow detection...", 10); + try { + final int sceneWidth = sourceProduct.getSceneRasterWidth(); + final int sceneHeight = sourceProduct.getSceneRasterHeight(); + + // 1) detect day time area where cloud shadow can occur + dayTimeROI = getDayTimeArea(sourceProduct); + + // 2) create north-corrected orientation image + orientationImage = computeOrientationImage(sourceProduct); +// writeDebugImage(orientationImage, "orientationImage.png"); + + // 3) create cloudMaskImage and landMaskImage + // as alternative the bayesian_in and confidence_in could be used. See TechNote. + // But currently the bayes_in.no_bayesian_probabilities_available is always set. so it makes no sense to use it. + final Mask cloudMask = Mask.BandMathsType.create("__cloud_mask", "", sceneWidth, sceneHeight, + "cloud_in.visible or cloud_in.12_gross_cloud or cloud_in.11_12_thin_cirrus or cloud_in.3_7_12_medium_high", + Color.white, 0.5f); + cloudMask.setOwner(sourceProduct); + final Mask landMask = Mask.BandMathsType.create("__land_mask", "", sceneWidth, sceneHeight, + "confidence_in.coastline or confidence_in.tidal or confidence_in.land or confidence_in.inland_water", + Color.green, 0.5f); + landMask.setOwner(sourceProduct); + +// writeDebugImage(cloudMask.getSourceImage(), "cloud_mask.png"); +// writeDebugImage(landMask.getSourceImage(), "land_mask.png"); + + // 4) create startSearchMask using cloudMaskImage, landMaskImage and search radius + // splitting cloudMask image into 2000 y-pixel slices but only in dayTimeArea + final List convolvedCloudSlices = new ArrayList<>(); + final List convolvedLandSlices = new ArrayList<>(); + final List slices = sliceRect(dayTimeROI, 2000); + // merge slices +// final Rectangle remove1 = slices.remove(slices.size() - 2); +// final Rectangle remove2 = slices.remove(slices.size() - 1); +// slices.add(remove1.union(remove2)); + + convolveLandAndCloudSlices(slices, dayTimeROI, cloudMask, convolvedCloudSlices, landMask, convolvedLandSlices); + + // mosaic the generated slices + final Rectangle mosaicBounds = new Rectangle(sceneWidth, sceneHeight); + final Rectangle mosaicTileSize = new Rectangle(cloudMask.getSourceImage().getTileWidth(), cloudMask.getSourceImage().getTileHeight()); + final RenderedImage mosaicCloudImage = createMosaic(slices, convolvedCloudSlices, mosaicBounds, mosaicTileSize); + final RenderedImage mosaicLandImage = createMosaic(slices, convolvedLandSlices, mosaicBounds, mosaicTileSize); + writeDebugImage(mosaicCloudImage, "mosaicCloudImage.png"); + writeDebugImage(mosaicLandImage, "mosaicLandImage.png"); + + + // create temporary product to compute the start-search-mask + final Product tempMaskProduct = new Product("temp", "tempType", sceneWidth, sceneHeight); + final Band convCloudMaskBand = new Band("__convCloudMask", ProductData.TYPE_FLOAT32, sceneWidth, sceneHeight); + convCloudMaskBand.setSourceImage(mosaicCloudImage); + tempMaskProduct.addBand(convCloudMaskBand); + final Band convLandMaskBand = new Band("__convLandMask", ProductData.TYPE_FLOAT32, sceneWidth, sceneHeight); + convLandMaskBand.setSourceImage(mosaicLandImage); + tempMaskProduct.addBand(convLandMaskBand); + + // use band math to combine mosaics to startSearchMask + startSearchMask = Mask.BandMathsType.create("__startSearch", "", sceneWidth, sceneHeight, + "__convCloudMask > 0.001 && __convCloudMask < 0.998 && __convLandMask > 0.001", + Color.BLUE, 0.0); + tempMaskProduct.addBand(startSearchMask); + writeDebugImage(startSearchMask.getSourceImage(), "startSearchMask.png"); + + final RasterDataNode elevationRaster = sourceProduct.getRasterDataNode("elevation_in"); + final RenderedOp croppedElev = CropDescriptor.create(elevationRaster.getSourceImage(), (float) dayTimeROI.x, (float) dayTimeROI.y, (float) dayTimeROI.width, (float) dayTimeROI.height, null); + final RenderedOp clampedElev = ClampDescriptor.create(croppedElev, new double[]{0}, new double[]{Short.MAX_VALUE}, null); + final RenderedOp extrema = ExtremaDescriptor.create(clampedElev, null, 10, 10, Boolean.FALSE, 1, null); + minSurfaceAltitude = ((double[]) extrema.getProperty("minimum"))[0]; + + pm.worked(1); + + doShadowDetectionPerSlice(cloudMask, landMask, slices, new SubProgressMonitor(pm, 9)); + // force creation of source image to prevent creation of new image by GPF + idepixFlagBand.getSourceImage(); + } catch (IOException e) { + throw new OperatorException("Could not read source data", e); + } finally { + pm.done(); + } + } + + private void doShadowDetectionPerSlice(Mask cloudMask, Mask landMask, List slices, ProgressMonitor pm) { + final int shadowValue = BitSetter.setFlag(0, IdepixConstants.IDEPIX_CLOUD_SHADOW); + idepixFlagBand.setRasterData(idepixFlagBand.createCompatibleRasterData()); + + final ExecutorService executorService = Executors.newFixedThreadPool((int) (Runtime.getRuntime().availableProcessors() * 0.8)); // Use 80% use cores; is this good? + + final Rectangle extendedDayTimeRoi = (Rectangle) dayTimeROI.clone(); + extendedDayTimeRoi.grow(0, maxShadowDistance); + final Tile elevation = getSourceTile(sourceProduct.getRasterDataNode("elevation_in"), extendedDayTimeRoi); + final Tile cloudMaskData = getSourceTile(cloudMask, extendedDayTimeRoi); + + final ArrayList> tasks = new ArrayList<>(); + for (Rectangle slice : slices) { + tasks.add(() -> { + final Tile sza = getSourceTile(sourceProduct.getRasterDataNode("solar_zenith_tn"), slice); + final Tile saa = getSourceTile(sourceProduct.getRasterDataNode("solar_azimuth_tn"), slice); + final Tile oza = getSourceTile(sourceProduct.getRasterDataNode("sat_zenith_tn"), slice); + final Tile x_tx = getSourceTile(sourceProduct.getRasterDataNode("x_tx"), slice); + final Raster orientation = orientationImage.getData(slice); + final Tile landMaskData = getSourceTile(landMask, slice); + final Raster startData = ((RenderedImage) startSearchMask.getSourceImage()).getData(slice); + + for (int i = slice.y; i < slice.y + slice.height; ++i) { + for (int j = slice.x; j < slice.x + slice.width; ++j) { + if (startData.getSample(j, i, 0) > 0 && cloudMaskData.getSampleInt(j, i) > 0) { + final PathAndHeightInfo pathAndHeightInfo = calcPathAndTheoreticalHeight(sza.getSampleFloat(j, i), saa.getSampleFloat(j, i), + oza.getSampleFloat(j, i), x_tx.getSampleFloat(j, i), + orientation.getSampleFloat(j, i, 0), + SPATIAL_RESOLUTION, + cloudTopHeight, + minSurfaceAltitude); + + final int[][] indexArray = pathAndHeightInfo.illuPathSteps.clone(); + final int shiftJ = j; + final int shiftI = i; + IntStream.range(0, indexArray.length).parallel().forEach(n -> {indexArray[n][0]+=shiftJ;indexArray[n][1]+=shiftI;}); + + // find cloud free positions along the search path: + final Boolean[] id = Arrays.stream(indexArray).parallel().map( + ints -> ints[0] >= 0 && ints[0] < slice.x + dayTimeROI.width && + ints[1] >= 0 && ints[1] < slice.y + dayTimeROI.height).toArray(Boolean[]::new); + + final int sum = Arrays.stream(id).parallel().mapToInt(aBoolean -> aBoolean ? 1 : 0).sum(); + if (sum > 3) { // path positions + + final int[][] curIndexArray = IntStream.range(0, indexArray.length).parallel().filter(n -> id[n]).mapToObj(n -> indexArray[n]).toArray(int[][]::new); + final double[] illuPathHeight = pathAndHeightInfo.illuPathHeight; + final double[] baseHeightArray = IntStream.range(0, curIndexArray.length).parallel().filter(n -> id[n]).mapToDouble(n -> illuPathHeight[n]).toArray(); + final double[] elevPath = Arrays.stream(curIndexArray).parallel().mapToDouble(index -> elevation.getSampleFloat(index[0], index[1])).toArray(); + final Boolean[] cloudPath = Arrays.stream(curIndexArray).parallel().map(index -> cloudMaskData.getSampleInt(index[0], index[1]) > 0).toArray(Boolean[]::new); + + final Boolean[] id2 = IntStream.range(0, baseHeightArray.length).parallel().mapToObj(value -> (Math.abs(baseHeightArray[value] - elevPath[value]) < pathAndHeightInfo.threshHeight) && !cloudPath[value]).toArray(Boolean[]::new); + + IntStream.range(0, baseHeightArray.length).parallel().filter(n -> id2[n]).forEach( + n -> idepixFlagBand.setPixelInt(curIndexArray[n][0], curIndexArray[n][1], shadowValue)); + } + } + + int flagValue = idepixFlagBand.getPixelInt(j, i); + if (cloudMaskData.getSampleInt(j, i) > 0) { + flagValue = BitSetter.setFlag(flagValue, IdepixConstants.IDEPIX_CLOUD); + } + if (landMaskData.getSampleInt(j, i) > 0) { + flagValue = BitSetter.setFlag(flagValue, IdepixConstants.IDEPIX_LAND); + } + + idepixFlagBand.setPixelInt(j, i, flagValue); + } + } + return slice; + }); + } + + try { + final List> futures = new ArrayList<>(); + for (Callable task : tasks) { + futures.add(executorService.submit(task)); + } + + pm.beginTask("Detecting clouds shadows...", futures.size()); + try { + executorService.shutdown(); + int stillRunning = futures.size(); + while (!executorService.isTerminated()) { + synchronized (cloudMask) { + cloudMask.wait(100); + } + + int numRunning = numRunningFutures(futures); + pm.worked(stillRunning - numRunning); + stillRunning = numRunning; + } + } finally { + pm.done(); + } + } catch (InterruptedException e) { + throw new OperatorException(e); + } + + } + + private int numRunningFutures(List> futures) throws InterruptedException { + int numRunning = 0; + for (int i = 0; i < futures.size(); i++) { + Future future = futures.get(i); + numRunning = numRunning + (future.isDone() ? 0 : 1); + if (future.isDone()) { + final Future doneFuture = futures.remove(i); + try { + doneFuture.get(); + } catch (ExecutionException e) { + throw new OperatorException("Error during calculation of cloud shadow", e); + } + } + } + return numRunning; + } + + @Override + public void computeTile(Band targetBand, Tile targetTile, ProgressMonitor pm) throws OperatorException { + // We need to place the data into the targetTile even though it is already in the raster. + // Otherwise, the data is not written to the product by GPF. + final Rectangle rect = targetTile.getRectangle(); + final int[] pixels = new int[rect.width * rect.height]; + final int[] samplesInt = idepixFlagBand.getPixels(rect.x, rect.y, rect.width, rect.height, pixels); + targetTile.setSamples(samplesInt); + } + + @SuppressWarnings("SameParameterValue") + static PathAndHeightInfo calcPathAndTheoreticalHeight(double sza, double saa, double oza, double xtx, double orientation, int spatialRes, int maxObjectAltitude, double minSurfaceAltitude) { + sza = correctSzaForOzaInfluence(sza, saa, oza, xtx, orientation); + + final double shadowAngle = ((saa - orientation) + 180) * Math.PI / 180 - Math.PI / 2; + double cosSaa = Math.cos(shadowAngle); + double sinSaa = Math.sin(shadowAngle); + + double deltaProjX = ((maxObjectAltitude - minSurfaceAltitude) * Math.tan(sza * Math.PI / 180) * cosSaa) / spatialRes; + double deltaProjY = ((maxObjectAltitude - minSurfaceAltitude) * Math.tan(sza * Math.PI / 180) * sinSaa) / spatialRes; + + double x0 = 0; + double y0 = 0; + double x1 = x0 + deltaProjX + Math.signum(deltaProjX) * 1.5; + double y1 = y0 + deltaProjY + Math.signum(deltaProjY) * 1.5; + + // create index steps + // Path touches which pixels? + // setup all pixel centers from x0/y0 to x1/y1. + // calculate distance between pixel center and line (X0, X1) + // all distances below/equal sqrt(2*0.5^2): the pixel is touched by the line and a potential shadow pixel. + double[] xCenters; + double[] yCenters; + if (x0 < x1) { + xCenters = arange(x0 + 0.5, Math.round(x1) + 0.5, 1.0); + } else { + xCenters = arange(Math.round(x1) + 0.5, x0 + 0.5, 1.0); + } + if (y0 < y1) { + yCenters = arange(y0 + 0.5, Math.round(y1) + 0.5, 1.0); + } else { + yCenters = arange(Math.round(y1) + 0.5, y0 + 0.5, 1.0); + } + + double[][] distance = new double[xCenters.length][yCenters.length]; + int[][] xIndex = new int[xCenters.length][yCenters.length]; + int[][] yIndex = new int[xCenters.length][yCenters.length]; + int nxCenter = xCenters.length; + int nyCenter = yCenters.length; + + final double divider = Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2); + for (int i = 0; i < nxCenter; i++) { + for (int j = 0; j < nyCenter; j++) { + double r = -((x0 - xCenters[i]) * (x0 - x1) + (y0 - yCenters[j]) * (y0 - y1)) / divider; + double d = Math.sqrt(Math.pow((x0 - xCenters[i]) + r * (x0 - x1), 2) + Math.pow((y0 - yCenters[j]) + r * (y0 - y1), 2)); + distance[i][j] = d; + xIndex[i][j] = deltaProjX < 0 ? i - (nxCenter - 1) : i; + yIndex[i][j] = deltaProjY < 0 ? j - (nyCenter - 1) : j; + } + } + double halfPixelDistance = 0.5 * Math.sqrt(2); + int[][] id = new int[xCenters.length][yCenters.length]; + for (int x = 0; x < id.length; x++) { + for (int y = 0; y < id[x].length; y++) { + id[x][y] = distance[x][y] <= halfPixelDistance ? 1 : 0; + } + } + final int numCoords = Arrays.stream(id).flatMapToInt(Arrays::stream).sum(); + int[][] stepIndex = new int[numCoords][2]; + int s = 0; + for (int i = 0; i < id.length; i++) { + for (int j = 0; j < id[i].length; j++) { + if (id[i][j] == 1) { + stepIndex[s++] = new int[]{xIndex[i][j], yIndex[i][j]}; + } + } + } + + double[] theoretHeight = new double[stepIndex.length]; + final double tanSza = Math.tan(sza * Math.PI / 180.); + for (int i = 0; i < theoretHeight.length; i++) { + theoretHeight[i] = maxObjectAltitude - Math.sqrt(Math.pow(stepIndex[i][0], 2) + Math.pow(stepIndex[i][1], 2)) * spatialRes / tanSza; + } + double threshHeight = 1000. / tanSza; + + return new PathAndHeightInfo(stepIndex, theoretHeight, threshHeight); + } + + @SuppressWarnings("SameParameterValue") + static double[] arange(double startValue, double endValue, double step) { + final int numValues = (int) (Math.ceil((endValue - startValue) / step)); + return IntStream.range(0, numValues).mapToDouble(x -> x * step + startValue).toArray(); + } + + private static double correctSzaForOzaInfluence(double sza, double saa, double oza, double xtx, double orientation) { + if (saa - orientation < 180) { + sza = xtx < 0 ? correctSzaNegative(sza, oza) : correctSzaPositive(sza, oza); + } else { + sza = xtx < 0 ? correctSzaPositive(sza, oza) : correctSzaNegative(sza, oza); + } + return sza; + } + + private static double correctSzaPositive(double sza, double oza) { + return Math.atan(Math.tan(sza * Math.PI / 180) + Math.tan(oza * Math.PI / 180)) * 180 / Math.PI; + } + + private static double correctSzaNegative(double sza, double oza) { + return Math.atan(Math.tan(sza * Math.PI / 180) - Math.tan(oza * Math.PI / 180)) * 180 / Math.PI; + } + + void validate(Product sourceProduct) throws OperatorException { + if (!"ENV_AT_1_RBT".equals(sourceProduct.getProductType())) { + throw new OperatorException("An AATSR product from the 4th reprocessing is needed as input"); + } + String[] usedRasterNames = {"solar_zenith_tn", "solar_azimuth_tn", "sat_zenith_tn", "latitude_tx", "longitude_tx", "x_tx", "elevation_in", "confidence_in", "cloud_in"}; + for (String usedRasterName : usedRasterNames) { + if (!sourceProduct.containsRasterDataNode(usedRasterName)) { + throw new OperatorException(String.format("Missing raster '%s' in source product", usedRasterName)); + } + } + } + + /** + * Returns the daytime area of the scene and where the sun angles are usable + * + * @param scene the scene to compute the daytime area + * @return a rectangle specifying the daytime area with usable sun angles + */ + private Rectangle getDayTimeArea(Product scene) { + final int sceneWidth = scene.getSceneRasterWidth(); + final int sceneHeight = scene.getSceneRasterHeight(); + + // test sun elevation and find first and last row with SZA<85°, daylight zone + // day flag is necessary because there can be an area with SZA<85° but it is not marked as DAY. + final Mask szaMask = Mask.BandMathsType.create("__SZA_DAY_Mask", "", sceneWidth, sceneHeight, + "solar_zenith_tn * (confidence_in.day ? 1 : NaN) < 85", + Color.yellow, 0.5f); + szaMask.setOwner(scene); + final int[] szaRange0 = detectMaskedPixelRangeInColumn(szaMask, 0); + final int[] szaRange1 = detectMaskedPixelRangeInColumn(szaMask, sceneWidth - 1); + // free used memory + szaMask.setOwner(null); + szaMask.dispose(); + + int szaUpperLimit = Math.max((szaRange0[0]), szaRange1[0]); + int szaLowerLimit = Math.min((szaRange0[1]), szaRange1[1]); + + return new Rectangle(0, szaUpperLimit, sceneWidth, szaLowerLimit - szaUpperLimit); + } + + /** + * Return the min and maximum line number in the where pixels are masked. + * + * @param mask the mask + * @param column the column to check masked values + * @return an integer array containing the minimum (index=0) and maximum (index=1) + */ + static int[] detectMaskedPixelRangeInColumn(Mask mask, int column) { + final int rasterHeight = mask.getRasterHeight(); + final Raster data = mask.getSourceImage().getData(new Rectangle(column, 0, 1, rasterHeight)); + // masks have byte data type + final byte[] dataBufferArray = (byte[]) ImageUtils.createDataBufferArray(data.getTransferType(), rasterHeight); + data.getDataElements(column, 0, 1, rasterHeight, dataBufferArray); + int[] minMax = new int[2]; + // todo - can be further optimised and parallelized + for (int i = 0; i < dataBufferArray.length; i++) { + if (dataBufferArray[i] == -1) { + minMax[0] = i; + break; + } + } + for (int i = dataBufferArray.length - 1; i >= 0; i--) { + if (dataBufferArray[i] == -1) { + minMax[1] = i; + break; + } + } + return minMax; + } + + /** + * Creates a north-corrected orientation image on a sub-sampled grid. The result is scale back to the original size + * using bicubic interpolation. The computation is based on 'latitude_tx' and 'longitude_tx'. + * + * @param scene the scene to compute the north-corrected orientation image for. + * @return the north-corrected orientation image + */ + private RenderedOp computeOrientationImage(Product scene) { + final RasterDataNode latRaster = scene.getRasterDataNode("latitude_tx"); // todo - better use latitude_in, but this gives strange results + final RasterDataNode lonRaster = scene.getRasterDataNode("longitude_tx"); // todo - better use longitude_in, but this gives strange results + final Interpolation nearest = Interpolation.getInstance(Interpolation.INTERP_NEAREST); + final float downScaleFactor = 1 / 10F; + final RenderedOp lowResLats = ScaleDescriptor.create(latRaster.getSourceImage(), downScaleFactor, downScaleFactor, 0.0F, 0.0F, nearest, null); + final RenderedOp lowResLons = ScaleDescriptor.create(lonRaster.getSourceImage(), downScaleFactor, downScaleFactor, 0.0F, 0.0F, nearest, null); + final OpImage lowResOrientation = new OrientationOpImage(lowResLats, lowResLons); + final float upScaleWidthFactor = scene.getSceneRasterWidth() / (float) lowResOrientation.getWidth(); + final float upScaleHeightFactor = scene.getSceneRasterHeight() / (float) lowResOrientation.getHeight(); + return ScaleDescriptor.create(lowResOrientation, upScaleWidthFactor, upScaleHeightFactor, 0.0F, 0.0F, + Interpolation.getInstance(Interpolation.INTERP_BICUBIC), + new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY))); + } + + private RenderedImage createMosaic(List slices, List imageSlices, Rectangle mosaicBounds, Rectangle mosaicTileSize) { + double[][] sourceThresholds = new double[slices.size()][1]; + for (int i = 0; i < sourceThresholds.length; i++) { + sourceThresholds[i][0] = Double.MIN_VALUE; + } + final ImageLayout mosaicImageLayout = ImageManager.createSingleBandedImageLayout(DataBuffer.TYPE_FLOAT, + mosaicBounds.width, + mosaicBounds.height, + mosaicTileSize.width, mosaicTileSize.height); + return MosaicDescriptor.create(imageSlices.toArray(new RenderedImage[0]), + MosaicDescriptor.MOSAIC_TYPE_OVERLAY, + null, + null, + sourceThresholds, + new double[]{0.0},//backgroundValue, + new RenderingHints(JAI.KEY_IMAGE_LAYOUT, mosaicImageLayout)); + } + + private void convolveLandAndCloudSlices(List slices, Rectangle dayTimeROI, Mask cloudMask, List convolvedCloudSlices, Mask landMask, List convolvedLandSlices) throws IOException { + final RasterDataNode sza = sourceProduct.getRasterDataNode("solar_zenith_tn"); + // convolution shall take place with float data type. We need to format the source images of cloudMask and landMask. + final RenderedImage floatCloudMaskImage = FormatDescriptor.create(cloudMask.getSourceImage(), DataBuffer.TYPE_FLOAT, null); + final RenderedImage floatLandMaskImage = FormatDescriptor.create(landMask.getSourceImage(), DataBuffer.TYPE_FLOAT, null); + // convolve + for (Rectangle slice : slices) { + if (slice.intersects(dayTimeROI)) { + // only convolve slices intersecting with dayTimeROI. Areas outside are handled by default background value when creating the mosaic. + double radius = computeKernelRadiusForSlice(sza, slice); + maxShadowDistance = MathUtils.ceilInt(Math.max(radius, maxShadowDistance)); + final KernelJAI jaiKernel = createJaiKernel(radius, new Dimension(1000, 1000)); + convolveSlice(floatCloudMaskImage, slice, jaiKernel, convolvedCloudSlices, "convCloudImage"); + convolveSlice(floatLandMaskImage, slice, jaiKernel, convolvedLandSlices, "convLandImage"); + } + } + } + + @SuppressWarnings("unused") + private void convolveSlice(RenderedImage sourceImage, Rectangle slice, KernelJAI jaiKernel, List convolvedSlices, String debugId) { + final RenderedOp curSlice = CropDescriptor.create(sourceImage, (float) slice.x, (float) slice.y, (float) slice.width, (float) slice.height, null); + final RenderedImage convImage = createConvolvedImage(curSlice, jaiKernel); + convolvedSlices.add(convImage); + writeDebugImage(convImage, String.format("%s_%d_%dx%d.png", debugId, slice.y, jaiKernel.getWidth(), jaiKernel.getWidth())); + } + + private double computeKernelRadiusForSlice(RasterDataNode sza, Rectangle slice) throws IOException { + final float[] szaData = new float[slice.width * slice.height]; + sza.readPixels(slice.x, slice.y, slice.width, slice.height, szaData); + Arrays.sort(szaData); + float szaMedian; + if (szaData.length % 2 == 0) { + szaMedian = (szaData[szaData.length / 2] + szaData[szaData.length / 2 - 1]) / 2; + } else { + szaMedian = szaData[szaData.length / 2]; + } + return Math.abs(cloudTopHeight * Math.tan(szaMedian * Math.PI / 180.0)); + } + + @SuppressWarnings("SameParameterValue") + static List sliceRect(Rectangle sourceBounds, int sliceHeight) { + List slices = new ArrayList<>(); + for (int i = sourceBounds.y; i < sourceBounds.y + sourceBounds.height; i += sliceHeight) { + Rectangle curRect = new Rectangle(0, i, sourceBounds.width, sliceHeight); + curRect = sourceBounds.intersection(curRect); + if (!curRect.isEmpty()) { + slices.add(curRect); + } + } + return slices; + } + + private RenderedImage createConvolvedImage(RenderedImage sourceImage, KernelJAI jaiKernel) { + final RenderedOp convImage = ConvolveDescriptor.create(sourceImage, jaiKernel, new RenderingHints(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY))); + // due to convolution value can be higher than 255, so we clamp + final RenderedOp clampImage = ClampDescriptor.create(convImage, new double[]{0}, new double[]{255}, null); + // normalise to [0,1.0] value range + return DivideByConstDescriptor.create(clampImage, new double[]{255}, null); + } + + private KernelJAI createJaiKernel(double radius, Dimension spacing) { + Dimension kernelHalfDim = new Dimension(MathUtils.ceilInt(radius / spacing.width), + MathUtils.ceilInt(radius / spacing.height)); + int[] xDist = createDistanceArray(kernelHalfDim.width, spacing.width); + int[] yDist = createDistanceArray(kernelHalfDim.height, spacing.height); + return createKernelData(xDist, yDist, radius); + } + + static int[] createDistanceArray(int kernelHalfDim, int spacing) { + int[] xDist = new int[kernelHalfDim * 2 + 1]; + for (int i = 0; i < xDist.length; i++) { + xDist[i] = -kernelHalfDim * spacing + i * spacing; + } + return xDist; + } + + private KernelJAI createKernelData(final int[] xDist, final int[] yDist, double radius) { + final double[][] kernel = new double[yDist.length][xDist.length]; + for (int y = 0; y < kernel.length; y++) { + double[] rowData = kernel[y]; + for (int x = 0; x < rowData.length; x++) { + rowData[x] = Math.sqrt(Math.pow(yDist[y], 2) + Math.pow(xDist[x], 2)) <= radius ? 1.0 : 0.0; + } + } + final double kernelSum = Arrays.stream(kernel).flatMapToDouble(Arrays::stream).sum(); + for (double[] rowData : kernel) { + for (int x = 0; x < rowData.length; x++) { + rowData[x] = rowData[x] / kernelSum; + } + } + final double[] oneDimKernel = Arrays.stream(kernel).flatMapToDouble(Arrays::stream).toArray(); + final float[] oneDimFloatKernel = new float[oneDimKernel.length]; + for (int i = 0; i < oneDimKernel.length; i++) { + oneDimFloatKernel[i] = (float) oneDimKernel[i]; + } + + return new KernelJAI(xDist.length, yDist.length, oneDimFloatKernel); + } + + private Product createCompatibleProduct(Product sourceProduct, String name) { + int sceneWidth = sourceProduct.getSceneRasterWidth(); + int sceneHeight = sourceProduct.getSceneRasterHeight(); + return new Product(name, "AATSR_IDEPIX", sceneWidth, sceneHeight); + } + + @SuppressWarnings("might be used for debug purpose") + private void writeDebugImage(RenderedImage image, String filename) { + if (DEBUG) { + final File outputDir = new File("target/images"); + final File output = new File(outputDir, filename); + try { + Files.createDirectories(output.toPath().getParent()); + if (!ImageIO.write(image, "PNG", output)) { + SystemUtils.LOG.log(Level.WARNING, "No writer found for image '" + filename + "', trying to reformat the image"); + final RenderedOp extrema = ExtremaDescriptor.create(image, null, 10, 10, Boolean.FALSE, 1, null); + final double[] minimum = (double[]) extrema.getProperty("minimum"); + final double[] maximum = (double[]) extrema.getProperty("maximum"); + final RenderedOp step1 = SubtractConstDescriptor.create(image, minimum, null); + final RenderedOp normImage = DivideByConstDescriptor.create(step1, new double[]{maximum[0] - minimum[0]}, null); + final RenderedOp scaledImage = MultiplyConstDescriptor.create(normImage, new double[]{255}, null); + final RenderedOp formattedImage = FormatDescriptor.create(scaledImage, DataBuffer.TYPE_BYTE, null); + if (!ImageIO.write(formattedImage, "PNG", output)) { + SystemUtils.LOG.log(Level.WARNING, "Retry of writing if image '" + filename + "'did not work too. Giving up!"); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * The Service Provider Interface (SPI) for the operator. + * It provides operator meta-data and is a factory for new operator instances. + */ + public static class Spi extends OperatorSpi { + + public Spi() { + super(IdepixAatsrOp.class); + } + } + + static class PathAndHeightInfo { + final int[][] illuPathSteps; + final double[] illuPathHeight; + final double threshHeight; + + public PathAndHeightInfo(int[][] stepIndex, double[] theoretHeight, double threshHeight) { + this.illuPathSteps = stepIndex; + this.illuPathHeight = theoretHeight; + this.threshHeight = threshHeight; + } + } +} diff --git a/idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/OrientationOpImage.java b/idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/OrientationOpImage.java new file mode 100644 index 00000000..7c0da415 --- /dev/null +++ b/idepix-aatsr/src/main/java/org/esa/snap/idepix/aatsr/OrientationOpImage.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022. Brockmann Consult GmbH (info@brockmann-consult.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see http://www.gnu.org/licenses/ + * + */ + +package org.esa.snap.idepix.aatsr; + +import org.esa.snap.core.image.ImageManager; +import org.esa.snap.core.util.math.MathUtils; + +import javax.media.jai.OpImage; +import javax.media.jai.PlanarImage; +import java.awt.Rectangle; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; + +/** + * @author Marco Peters + */ +public class OrientationOpImage extends OpImage { + + public OrientationOpImage(RenderedImage lats, RenderedImage lons) { + super(vectorize(lats, lons), ImageManager.createSingleBandedImageLayout(DataBuffer.TYPE_DOUBLE, lats.getWidth(), lats.getHeight(), lats.getTileWidth(), lats.getTileHeight()), + null, false); + } + + @Override + protected void computeRect(PlanarImage[] planarImages, WritableRaster writableRaster, Rectangle destRect) { + PlanarImage lats = planarImages[0]; + PlanarImage lons = planarImages[1]; + int x0 = destRect.x; + int y0 = destRect.y; + final int x1 = x0 + writableRaster.getWidth()-1; + final int y1 = y0 + writableRaster.getHeight()-1; + final Raster latsData = lats.getData(destRect); + final Raster lonsData = lons.getData(destRect); + for (int y = y0; y <= y1; y++) { + for (int x = x0; x <= x1; x++) { + final int x_a = MathUtils.crop(x - 1, x0, x1); + final int x_b = MathUtils.crop(x + 1, x0, x1); + final float lat1 = latsData.getSampleFloat(x_a, y, 0); + final float lon1 = lonsData.getSampleFloat(x_a, y, 0); + final float lat2 = latsData.getSampleFloat(x_b, y, 0); + final float lon2 = lonsData.getSampleFloat(x_b, y, 0); + final double orientation = computeOrientation(lat1, lon1, lat2, lon2); + writableRaster.setSample(x, y, 0, orientation); + } + } + } + + static double computeOrientation(float lat1, float lon1, float lat2, float lon2) { + return Math.atan2(-(lat2 - lat1), (lon2 - lon1) * Math.cos(lat1 * Math.PI / 180.0)) * 180.0 / Math.PI; + } + + @Override + public Rectangle mapSourceRect(Rectangle rectangle, int i) { + return new Rectangle(rectangle); + } + + @Override + public Rectangle mapDestRect(Rectangle rectangle, int i) { + return new Rectangle(rectangle); + } + +} diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrAlgo.html b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrAlgo.html new file mode 100644 index 00000000..97528e78 --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrAlgo.html @@ -0,0 +1,141 @@ + + + + + SNAP Data Processors - IdePix AATSR Cloud Shadow + + + + + + + + + + +
  + IdePix AATSR Cloud Shadow Algorithm + +
+ +

Algorithm Description

+

The cloud shadow algorithm is based on geometrical considerations alone. With the cloud top height and the + illumination direction the shadow position can be determined. As elevated objects are mapped in their apparent + position on the ground if not viewed directly from nadir, the sun and observation angles have to be transformed + accordingly. In that way, the algorithm translates the question of shadows from spherical geometry of the Earth + observation and geo-positions into the space of the regular projection grid.

+ +

North Direction

+

As all calculations of the shadow are translated to the geometry of the pixel grid, it is necessary to calculate the + north direction (also called orientation or bearing) for each pixel individually. + The orientation for a pixel (i,j) is derived from the neighboring pixel (i, j-1) and (i, j+1) from pixel-geocoded + location:

+

+

Defining a cloud mask

+The following cloud flags have been combined in a cloud mask:
+Cloud_in.visible (bit 0), cloud_in.gross_cloud (bit 7), cloud_in.thin_cirrus (bit 8) and the cloud_in.medium_high (bit +9). +

Adjustment of Sun Zenith Angle for Elevated Objects

+Under tilted view (view zenith angle > 0°) elevated objects of unknown height like clouds are projected along the line +of view on the surface, so that their apparent location differs from the actual position over ground (nadir view). +If view and sun azimuth angle are positioned in the same halfspace, both left or right of the nadir line (center line of +grid) in the projected grid, x_tx>0 (VAA*180°), SAA*>180° or x_tx<0 + (VAA*<180°), +SAA*<180° (angles are corrected by +orientation), the geometry of the apparent sun zenith angle which causes the shadow position can be described in the +following way: +From +

+follows +

+

For view and sun direction in opposite directions (x_tx>0 (VAA*>180°), SAA*<180° + or + x_tx<0 (VAA*<180°), SAA*>180°, angles corrected for orientation) + follows accordingly:

+

+ +

The sun azimuth angles are corrected by the orientation (North direction) at the current cloud pixel, so that they + represent the azimuth angle in the projected grid coordinates with 0° in upwards direction on the grid. The view + azimuth angle is replaced by the tie point grid x_tx, which gives the distance from the nadir line at the center + position of a pixel. It changes its sign from left of nadir x_tx <0 to right of nadir x_tx>0. This is the easiest + way to find the viewing direction (without interpolation and corrections), and it allows the algorithm to process + subsets of the swath width.

+ + + + + + + + + +
Geometrical correction for apparent sun zenith angle (VAA>180°, SAA<180° or VAA<180°, + SAA>180°) + Geometrical correction for apparent sun zenith angle (VAA>180°, SAA>180° or VAA<180°, + SAA<180°) +
+ +

Determining the search path in illumination direction

+

Starting from a cloud pixel, which is defined by the cloud flag expression, the illumination path is projected on the + grid and all pixels up to a maximum distance are identified which are intersected by this path.

+

With the adjusted sun zenith angle θ*S and the azimuth angles adjusted for North + direction, so that they represent + the azimuth on the grid against the Y-direction, the geometry of the illumination path on the projection grid can be + fully described.

+

Orientation (North direction) at pixel [i, j] is calculated by the positions at neighboring pixels
+ p[i, j-1] = (lon1, lat1) and p[i, j+1]= (lon2, lat2).

+

+

The theoretical maximum length of the projected path in grid coordinates is defined by the range of surface elevation + and the adjusted angles in x and y direction (spatial resolution 1km in AATSR products):

+

+

The relative grid coordinates of the start point at the cloud pixel at set to (x0, y0) = (0, 0).

+

As the spatial resolution of the grid is quite coarse with regard to the expected cloud top heights, which are + currently fixed at 6km, the maximum extent of the search path is defined as

+

+

With sign(x) defined as: for x>=0, sign(x)=1; for x<0, sign(x)=-1.
+ For all integer value combinations between (x0,y0) and (x1,y1), the center position of the + pixel is set to relative grid coordinates + (0.5, 0.5). The distance from each pixel center to the + theoretical line of illumination is calculated. If the distance is smaller than 0.5*√2, the pixel + area is intersected by the line, and the pixel is potentially a shadow pixel.

+

+

For the intersected pixels (distance < 0.5*√2, relative grid coordinates x, y) the theoretical + height of the illumination path is calculated as:

+

+

Where the theoretical line intersects the surface defined by its altitude, the shadow can be found. The discreet + nature of the grid calls for a height threshold, so that shadow pixels can be identified:

+

+

The cloud shadow flag is raised for all the pixels of the path, which are not masked as cloud and the theoretical + height intersects with the surface elevation:

+

+ +

Algorithmic Limitations

+

Cloud Top Height

+

The AATSR Level-1 product does not provide cloud top height information. Therefor this values is predefined to a + value of 6000 meter. The processor interface allows to adjust this value for each processed scene.

+ +

Limited to Land

+

The detection of cloud shadow is limited to pixels marked as land. Above water no shadow detection is performed.

+ +

Limited to Daytime

+

The cloud shadow calculation is limited to the daytime. As daytime is the part of the orgbit considered where SZA<85° + and the confidence_in flag day (bit value 10) is raised.

+
+
+ + diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrIntro.html b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrIntro.html new file mode 100644 index 00000000..59c252be --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrIntro.html @@ -0,0 +1,67 @@ + + + + + SNAP Data Processors - IdePix - AATSR Cloud Shadow + + + + + + + + + + +
  + IdePix AATSR Cloud Shadow Intro + +
+ +

Overview

+ +

The nadir product of AATSR 4th reprocessing is missing a flag indicating cloud shadows. The IdePix AATSR Cloud Shadow + processor aims to provide such a flag over land. + It has been the goal to calculate this cloud shadow flag based on the information in the Level-1 product only. From + the + cloud flag and the geometry of sun illumination and observation almost all necessary information is given, which + allows a translation of the cloud shadow algorithm for OLCI to AATSR. The information which is missing in the + Level-1 product, is the cloud top height value. Thus this value can be provided as a parameter which is then used + for the whole scene. + The general idea of the shadow detection algorithm is to start from a pixel, which has been flagged as a cloud, and + follow the direction of illumination until the surface is reached. + This Idepix processor does not provide all flags which are defined by other IdePix processors. This one sets only + 3 of the general IdePix flags.
+ These are:
+ IDEPIX_CLOUD, IDEPIX_CLOUD_SHADOW and IDEPIX_LAND +

+ +

Further details are provided

+ +
+ +
+
+ + diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrProcessor.html b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrProcessor.html new file mode 100644 index 00000000..b05ee881 --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/AatsrProcessor.html @@ -0,0 +1,91 @@ + + + + + SNAP Data Processors - IdePix AATSR Cloud Shadow + + + + + + + + + + +
  + IdePix AATSR Cloud Shadow Processor + +
+ +

Processor Description

+ +

I/O Parameters Tab

+ +

+ +
Source Product Group
+ +

+ Name: + Used to select the spectral source product. The source product shall + contain spectral bands providing a source spectrum at each pixel. Use the ... button to + open a data product currently not opened in the Sentinel Toolbox.
+ Supported Source Products: The processor supports AATSR L1 product from the 4th reprocessing in the Safe + format or converted to e.g. BEAM-DIMAP. +

+ +
Target Product Group
+ +

+ Name: + Used to specify the name of the target product. +

+ +

+ Save to: + Used to specify whether the target product should be saved to the file system. The + combo box presents a list of file formats. +

+ +

+ Open in SNAP: + Used to specify whether the target product should be opened in the Sentinel Toolbox. + When the target product is not saved, it is opened in the Sentinel Toolbox automatically. +

+ +

The Processing Parameters

+ +

+ +

+ Copy source bands:
+ If enabled the bands of the source product are copied to the target product. If disabled, the target will only contain the flag band. +

+ +

+ Assumed cloud top height:
+ This defines the cloud top height value used by the algorithm. The default is 6000 meter. +

+ + +
+
+ + diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/Aatsr_IO-Params.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/Aatsr_IO-Params.png new file mode 100644 index 0000000000000000000000000000000000000000..4f2857a9e735fa455e0bd20a73e7007dc7c78d7b GIT binary patch literal 14193 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�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 literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/IlluminationPath_geometry1_small.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/IlluminationPath_geometry1_small.png new file mode 100644 index 0000000000000000000000000000000000000000..3933454f0d23b8f9e69f84ece92cdc3e1da5a07f GIT binary patch literal 20151 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 literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq001_orientation.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq001_orientation.png new file mode 100644 index 0000000000000000000000000000000000000000..fb207ba346a34e1dd192e64e5c8e15def60db261 GIT binary patch literal 3766 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 MZ=2q#GO&;O52GQ5!T?RwF5DNeRU^6n*v!GWT zJskcxP0vX|NqzLf;B9de3Ml(5vPy4Gx$Bzh0sxhVA_U7EKS_F=qoIhnp@_)g742q>pM-*LgY*>d z@IO5}E^&wVb!dzQzoHysag#%%8LjQE#Hw_>l%W8H+hd$z%vWYGIvfcJ2pKtOILeO$jxm% zM5_mpLQtD2Ym!rt=j&si_xAQw^0Ewx(he<}`Z8$AxRc@?$Ged>o%_X7#_hbwG+&7S zk4`);j?~LrYX&ai^|f7}s4jVx{SL5z<>%ylzDms>vKBSPVfDCdH(sRaI!i|}GIC?_ zB%;q+a{1!^F1P%-L|Fjaci>f<^Q2-J=(WL)!O;h9j2xwOBp#ft?9q8+T0h9zR89eS zPTWl=B1y=6E>400GO7=7y>tTp&_aSqqhdE>py9Yb-lsP1fb6FlOn12W%5ljU$Kj(W%+E+wVqLT|16@8=;rl3run3VOEywPZiKNK^`BHA2W3*i zspeNhlMHU=9))C38&W9=alxNE2<^ zU|`W5xH>QUey!{ygrD`8iLo(HQ#mO7>i0x1;I zIVL2p7q|6M?QK8yRYIwc8f+i(5tyH78U}y zisb$l(Y2w{hO90+Ij_143Yuqu$MLZunpH}(+8EjgV2f5c3am z8Vo1hzhXy1y;Kt#jnUV)t(b4F;iLJ$_qXPzouQOfo~o!N<5y(!KJE#IBrM2}-MYF5 z`slG`m}B`jcP{T*fW1>C0hCv!Ws9pN3qcDV`N^-WP9ZFA_3Uha?f6k@Uy%t9h@ymr z{VX;rs5MHEK|`t)yD06ndyk%PPB*TZWoXPDOLoMH`<`JJ>8$?pj^}2Kh}Xl>GEwFZRa-dI>Nt7iH|igE@~2U13&RJIN|VZD?n=HOukgj}7z%nBnj zw^0ZHn+rS*86`gn4|PMZpvr^PmUpH&<+8zZT|VJlz|jD2G^Zz8eDy-~UmQeoM>2Mn zl-8nxlPuL*j`udw)3pOWLhzd21&{}By>I5!9*xcR3n;)Anu33C_T#bxQm^?u_*y6V zrph@W!QCtbxzdC=JUW>D^yjgX%H`n;2ZJR&E{A&?O^5asP9c+Z-i7HJUd}a7a@DW! zNH(sGyf?l|6>?!;&q~MkP7>T>C#w*~LR3*VZP(e8 zZ-5YY@E?!BE!PkB0~^Z>^194jzItYRQ6wPo~`W=E=B03S=uC(UV*U z6i`%A#--f~Jf$YzR{pStH>*Jls89+{IkOF&eOAr8Q2lT;aIGU?)c}!#rJvqmYDQQx zV+i((Tz?+)f=jYW92o1h@l+gpidfR)3ZMR%cTdZ;e)jT)(Ha~PR4gTjX{vaR=!K-_0I zVRL-)R?md@ss2tQ-TNiqp5&L)FGDqQ06J%%U4IKko;XYXIw_Frm{TvYR?V}bcwl3D z^KW#YbpHL#{(;T^es=#OC;wri-g7H(q^;_8GbMFK+5(ao%8qm89lBsG-mzY5O9Ae;=KJ%K#lS>;I#rq8_(c^ko8npNy6{vYm zuWv+Xl-+M6!s~y`lYyRkBLf3-n={SdTOTlgxlM4Ye`#ub&q*W(!|_phOahrMGJDKa zM@jwlFg?#r0u$__HzS@%t+K3!04WW4Fq-AFcNN@AM`2@37ww0rNXUg_J|&< z&^&YM5bL#OluvG=V7w9BVBnr%h{f2o?fp720t7gBjfos_;0EG;B~_@8{E??z>A}f{ zmArkCcCtl`<5PsLnd_M_Eq;R{2$JnWfw3NL!TjwE>({e2y_ZbBYMsG=uS!fyI@**- zbQLoA_~h_b()Z}08=-?a>Q2$+doSW6FVwvT{ijU<(sm%*E+WvX5fbMPeq-&p^hUEdxFrP1bQBJJd zk}p~U2%lUYQ4UO{mzicfCM+? zcU)py35(j9jm>o}IWl^=suNW3>wQeLZIs7fjQqz08fF}doB6W&H9oFZr8`xCk-nK; J8Pw_JzW@{|V~zj- literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq002_apparentSza_2.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq002_apparentSza_2.png new file mode 100644 index 0000000000000000000000000000000000000000..5ceb73493ff65a6acd08ac1fc154d8729f1081df GIT binary patch literal 711 zcmV;&0yzDNP)Px#1ZP1_K>z@;j|==^1poj5Gf+%aMgRZ*M@L7AiHQ*r5dZ)HdU|@bwY8X-m}zNg z-QC^L(9k0zBkb(#r>CbhG&IA*!&g^VD>B!{00009a7bBm000ic000ic0Tn1pfB*mj z9Z5t%R9HvtmFtq*APj{;2+Y;+{!iN@nXc`Pok{mcr!)08lbB!$9SK3q!^6YFe~z8c ze+hEzjR_0IG-o~|TP}HyKc_}^ZH~X7o4WWlRfiZ zgfF8ese~=PTHVM+O`@7yA>O&9IuLdbm({DN#R1g@x@f~#p7Wbt8sLCx6J!(Rvo)^v z6E8B{=o%Jmab{*}y@ylZEx9AAtq*L`(KxL5DiO!0xa-DNZI!Inao4uu&Zu)HA#mTkq2$!HYE`qHy*NgcQMsE1E;t`RpJfUM4X zeyw=q)k@G8nkyMLC`UYmg8;oop>6!ZP5*i$e#n~(_?BSlrrxjkZt{<`p=fW~;g()L tck;#l;J*>ra0015c1^@s6s}B_@00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1)51jK~#8N?VGzx z9ZeL#$FKJh?L;ipQV=v65N!lsDMYa_MG7IHXkis%P^<(+!A3AqAz%?uP_a=lO)L}( zO+-Pl@IkP!GCu!+`|WR>bF?wm8{%$YM+ObR(DizOibF?Wk4 z5Uc}Q0>wI@B~YvbS^~v7pe0bO16l&bI-n&`tOHsC#X6uRP#&}c*3{IPlI5uqr~?iT z4yyF@bd{8pq`JGiO{-Fii;HS(Y)n;DRH*j$c6D@gWO^PK+uPfE5usmRUY@Q$1%Ceg zsqKPZ*l%iT%Jjqme+%|vU|=9rU0rQz_fJ<>SLpfk=b^*H!_evJY3SLrXQ8dFEz^55 zer|4VXklT&wA??azp}DoYWE9zq0{K-sIH?=Q&W>J#{+WSVXj+XH^xg8*sZOtP1_B* z&@*15M!+9Gewfnzv%0#fK7RbDmX?-OPEL->$jHzu>H7Lw_Y(o3rKLs9&(9|$0wy}D z5+UBdf3I3wTXj7B`~LdqL1GQNOTgNxMWP;r%W5N$<7k1?dW&giFbHDUZTE!M;4(Ny za1Sg-ku8S_r|t#qyc>CmvHc=4+;#Dc7h+KNWFkA;B#whDOt$-d=0gm?Gt|AdRlXA` z2NzBpFCwoWc+M@iEI4#RZe(`b*01gOj$0qO_;$R+bO<>+J5yz4Wx8BiTB`4EN=iz? zTTX3lt!HRv`=#9(JA644pd5wub{q@u-o3l^9j}XL{DSNx)NC!t!oeXD(gNmyXE-Ez zZL4#0b6O|298geDpznTQo=EcLDlaeB?d~?ezY;Jm+p?rPg@uKt=NEo#_vOnM2o`j5clK|*&5W_ zw{LZQW@bi5T2}1-{{EebJBAY_qg`Ich2-R9Q~E_uPmh|Oo>mZ{NPD zl#~=xQ)*~vNIBbYIKub$_p6462DP!Vp+0~9tlRDrb`v)^AB(!Vxmn9bbdHDb-@mKW z)KpVb>eHuB%GrK(kYK?$Tf1_$@34K*nXzQo^dhPQ;%GPl-pp@wCnqPm{mq*vkf+>({TfkY3v_irlrz|6~i6?QnN@SIdEsSY%aI zRqEx-muhcsPs@m2LS#KsX935R`N8lku-@KYU5|vZVo4MHz;?R1xv6Di0UjS8haCl^ zPw;CyQjV`*zv?pc)z{ajCMG6y9q<`(Q09_A@>|^;BY7f;E6FG)B1yV=g*$c1JmXGI zC6VPl>Rw5@oU(bwaX!;}gCxoF-9#dCh(73vOrkTg(NEcZus|*^oduaY`uKLF9@IIl z%D8@re6vu>X`q-cVOpr&rNa zh3G^yk{t1|Lpn7)Jgg%nkx&jbcM;PeB+;h75`m}iQ;)Ol|^K;F}$cSlu{17zQv0~B5{$H>qP##wuO(u?}bn6zhPN08#2+A^$80ZF3S800000NkvXXu0mjfAH(3? literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_1.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_1.png new file mode 100644 index 0000000000000000000000000000000000000000..406d4d7ae8385e2e58a847f8b174951c0adcb6b1 GIT binary patch literal 8462 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 kMv=aR|1(4D!@_2N)JLIsgCw literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_3.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_3.png new file mode 100644 index 0000000000000000000000000000000000000000..8f00a633a569a92d85b1610de215480e20312ffd GIT binary patch literal 3686 zcmZu!dpHyP+gC^uLeJzubEX`V$Z?LD+DHP zYRJ+Umdu%)nPFbf?|J`x|M-5tpZmT)*Y}Ulb=~)Mf0FHOE&0#=d5(jFgWn2l?!duu z8gPQe&Yn5B{nOy;C(o%62TN0q4`hkOlYk3uVq?O=QHS9>^yEH?d7pqGAsie6AOAV0 z`U2m1pZs)SWo~j0<+hqfALQ=?_Vw)vD$UxK3QcHf2{#DO7TdUNzjvTu#CfHApz($6 z>1F;6%_?~9plKa`(U?YIn}!~Yla{>NP*St`hM)mGIyD+t0MDN^Y@Hu7B+G8yCeDwI zjb#r;#eB`p7Lgpy`YD42%Lyl&`~7^j2>%DjU`d6^eCYosWg3M<0smK*Ra5zwO1bs$ z!3pbxP?6ePoAh7kAdUwBFqaL3=`jb@w6=&4m(5LG)Ow+7{eM!ks>Qd91!UAQ&i%j^ zN$XYPG~JN7QY4mS?1pEGU#)X?v1Lo5H4UPewSnUezR^4a5@746iOWA~_ELeMjPfQf?>TVOD|&6+odF?mb<06W~?55K&WC-vMTo>stc|1~Pvp6!vvp*aJfOxsK zKW*H@wbX^b6)Zyabkv+SlV|%lAAy}1j@byxy%p^I)}h0_f{Lr->9@r3_Ged}cHnlCTs-TuY_f1;0D|_Aa zb**6m+}xj+U>a_Y^cSra@$XGi5h;1bGuQcY-^`neAoD~Z0IsIcm$(po5jnv^q+yFk zexyy$fKP-!EC<{LIDB5p5%n_Jh9YF0;)>4HOs@0`ek_c*3p?z|Tv0u8NxGg7fnJ|d z0JIgd8IjxQ>Ve+K?-CUMmoA6HAHII27WGp(A7NrXQwcb#^6Pp^pb9zPa9LQsIcTQ$ zt^DA08;n}(S-qwD+cHgJ5mYHm0S7rq)6gs9|He7Q0 z@Nf~J_Hf~~RPZtTAdto2?qstnBljkeBl`1~4NyNpigx)Eud}Z$AX2X#ZS(;<1Yiaw z0<#89a71p(>eT)sxA;fD0b$ z%a3@J(?pMHmG9iq$-hh9O2>fMRDXKMh6yT~kY;&6WpO0a)2KUiRA?fzu(oBW!(lPL1{M37_I9p9d*p0L-<_JY&? z(Ys^tj<$ex`NfC98UpUyys;^(v2pFo5{JnjyWNM}l z#2tQ-Wmk$rELsb0^iDiN|DqbJv!;MMd&jI!y=2HkzN+2ajE0r zw|)WTZ*Q6O_PCUAew(TT`nsBHldV70jXIdW_?iOgM!<#=OU&+0mKt=a z;AnroKn>z~5VS_E`v{8PS^jar3T)qTa@mZNx6VXOY9!yNd&dEAA|)aok~YU5*X+Zo zXYyX~o^^F^fBK#0V3pQ1c`_@aUn_dnbC~HU+U7n<6a;LY!wy747d(Lqa*TZ4kg^}DEyYLvG~&J<)zYgg3;y-5S*NN8-I-}Mt*DJh zfue={j6s(NO5Ip$ZOBxq`$g*%I}utve6UTu(K;CB5k-x)dVw-W{^lgxs{F&=2ERUJuy*>|)X* z*9_egQU6FW`I29JB1P=_QyDhOeLwBfDR*l6e5%gW`c5`QCtzYBf&zkk# z7V{qwU7NFEnMv;!g2@h%UoB{Ih}og@Va!O4cdGt1PXwG`k!Ag>tqNhrt!?h1vpcCD zR^H$^F4cZ2S2clJ84LJeBGXh&_k9bHuU}v@4c25S*TV=z$PHrEswbLtrDYRgO(W$u zs#+dTZ=jcGb;TkFM$uzzCM^ILTmTapFI8=n%%6=TR)k5T)6T0H3@pWWtiC~ET8a)K zw3crn?{F7bjWdEKi3ad07!k9zjpt$CqFD*sT5t09x!(xnSZiwC^gt}R5~Sj}#c9M# z&X?3Pe)tCNL-buak8Ts&lxj7%?ONk)RdQy>3u1CLRa{g6X^d|efUGf8(*I$E|u=fSVw z9-7((BzrCD`*T&M<$4~%z1f$X7knb_iSeAm&N8$~!w`MNB9J$KzstKPfyC@`t=lDNk4I zss+)zVTaA=7deLfF<#$y8R9&A7kr{erP6S{Yf}KUbCsZHtiIj7OY}I<30jKjlSV8T z4anR~%+*H*Jl#9ZXmZU)co8gomfhM=!|hvS{l&?UA#Pf}q%^dOLVbh-}|r;Xzp3e?Z^ z-w3CD(+QjkwHgw*`Mx=9IrErO2dIT1mi-=60vdlQBXkt|y8`#p&XX4_yM{$*ZHSs0 zXzM7n`AJdcDph5DR?~Zy|0jtDbVr!5*WL0A*}ay?jK(G0Y-*X^`-5pW9D$tNJrf0N zf6(cFn!#MEta(UC->}qr1!Vjk<9RHBKk3BY<5c(HP*}(v^&X)A3|(5HkNWTw6JMQ! z7o4WndAVhF525R_EGiPXIjx+~i<5kpE`aWh6JTgTIR$~EF7A&(8y_<-C~UNG%;z4E zu(AQi>?75gfgs&@`WiRl!yf2s)jCkr@EW2N5rp6}n<*0yToXSnna;g&8M0#y{ zE_X7&IOKuWV2)1BjeQSGg$aXKkCH8NABiM=RiW2u1dKOG;Q(9ISD(@lF9n0-jsxvgSnA0293eLEPT&z}R6@P8x(_M+aj2M=W&7Imw43g$s^Ahc~&Q5nL zMH1b8(VB}U+Ot<51DF2jS6P>>9n&CJq##Fb~YEaG}Da%F2MaVR;pPX<*p$sAVP*;G4>Wrw;`kkDPg=%DxB)uDWZ zBbPQoyFOScz{fJ2Yw<ufQy)IahQ3I`9)a7WOqd@(V4*%I&V z@AHt*n-O-;I&Xu4yE*3SAOEJP$uK2S4)c1H~RMQ(&DXTJYiMlu?HH$#UhY{s63 z_TKN)>2`ZmyZc*#nvB9q)^YDHYQ;QNWy{%>@0U7zsh6hY;yX-BZswMJxr%)%7X-Dy zU0t2_ut1-q0kVX-Y!jqst85%Ccqp(55?Xo_aL-Jrcd)so;y};XEsB3^-&-Oc+xZHl zmE3V*DcK=NJtpibwngQQ~k-X_tYa8Wl@Cn5P3PfxI?B-*q-x)#19BsaRQH_~43 z5=RmeHYz<$^(Sv_ce3%NcYfh})6wXmTG#`=Y92l5ewjaHR9|gq_)s#@U)tqp?#n3O zXI}W($%8awdThA`V79c}rya{T(E2JO0?sF(+%HJil`H*!D@qh+%+#FbWcWIt;3<7i z=1+nrgC`Hmf+n3tGNkS;M=)v7@LINCb>|X~5lnG9VR8Rn2`A$qni{oKl)&o(S4KLI z>#C#dx2Lb`U-imz4vQ z^ml)_G!@?o8`@oHT384~@7&;0Va;V*p8n?GwSe^Z`t{G#1GZ6G26|zwK&SD@^ODDE zdX8-^rcXKR{svVafg45a)Di-)VG~p>Ycms*^TqJC-+ASbXH~geFlRnVs;gLmfH6x zzM8@LS3iy%86&m|=q>~jFHUr3{3q(q`^MtyinHHtmp4Qfz~4gT$a+z};lEE)e0OH+ z4on*vG9^SGH~~M-3dt!|sf&sTi#1Ej$vw#kVoLzo zXj229_*KJ6SXskOosK7|QXN-+J@71#_c|Ik^SrFW0ZX_X&|`Wj=j}@LnXBW$pT(At1w;9T+qrD^&F9cI zY_ifS-hHy{^#}-Gro5izd;crGzMfXk=B6EqyK|7yEIY@)??#R|-kxfbUwqr8m6#fW zTT8!a1c1(#)Ouchc3AVY5hv>>`CEGwp}g08xFTDOJLu(x!oVhDE8Q^*KYu0!8r)WJ z=wWDEdQd9nBr}N(S?;8l^uwR*#KaF%TsS}=WK?~x+1-vw_gYSK=Ds<=+agzAx|>S& zTwLP!4mf{R2OT<}&Uv@tv@-~87bkOz_Eo2Rn9XADu_GsB=U0m|nkk#W?3iH4ZU;5@ zQSa01M+jDaqIt1HO)WR5GC!CDuKvSCX>|#IRYO^?Z zrC|Jvuu=*=i$v^*!s&Kp8?uCDhkJ{6_17LgHFttdeF)**x;d__dDn*C+pF*9sm!N8G{`jPZcpKJb7WNeZ6A=(u$D@ipOe6S(@EV* z96E9%zrf$u>O?R4M#hYvWhkb5G$9SUHhTAX4UJLa@wRI&sSURvlH&2pX@6I$ z*Z><1c^3AYw3aTL36Jt}L#(`)!l=3SbDyev^Y@$WI;$qxW~heLE5BZeutNH|L7XXq zUmZ`slke#$Eu@K=I#UFPaNLDL25(q*sh|A~SFx{@sbk+60cE1i>qTErnkC6^jZ z1!Tq@bl$m}@%}>`hx{j?f=asx^~u0F{GZ7D8e-$fV(BvWqRHIgEm7~bc-527AqU+o zW}ae|pm*!pH3Up$*v{1g_oYL!(oo2Q`&U z?G?8ecx5=Exb@pc3Zgy9uvh2Xm7Qh~r^g~y%N_5-?}lmQ^);8r_9XDckSy=DU40tK zilmVl%6RQpA#PdQr+h=(gP#;KoFUu0hYmzTQwNiOqo^xnm6)kQ73z*{X`cJ&vO{-Q z@zxILtmH+GxDMji*sCN(^Xl?2?h0kUz$ z>LBCysd}^a*XfwPByKbUb16?R zpHILCxB=nzP*>lL*odQ*)2mCoH)Nfr#mL)bR1e1d4;HVIIW2TM&&sA~#`(VK>get;lgkc}gv#k)5?BKIXC9EN>c zXjsG83|*Q0!$uQbVt=qR-Or{XfBVzQV!9#Z`!HzgtQ886(-agEG$K5@W(x%7}=?sNkFft-*F1MaerEm*0uE zmqL5{NrPYslRv>T{+h6{KT`zBxSs*jmHCFKWWYwpY+8cYg$by%hG{Ei52FrB3PO!p zarMbq@x{9Vy8ofw9u}D^LJAtDV?+mpdy$4DrQk!m0u~$R8E5u5fCovJPNQBg_^X_d zMVwufXr^|1Y@Sgce>EyRHT>fb)J$0-b^oi#PGPjHL$UqxbiaY3NPOx511+1IwuVxn zsTQv3D?lpSJ+-1xWjs3Y4@;pPZ5tbTQ?Vh^kqbVwG1$(Ic0%<@sWH3)@ZrY zu{GCkF1*^YcPM28%roT4Edn>O1dlqUc{)pnsU@0RgLhPqnd?E-HHvHAGI_y&eP!}X zyY@AEm#hE(7+ur-|J{HPgU%29%SX=}ys|@x@oSa;8u^ubd^f(dJCj(nLK>}_-+pV_ zMQ*RiUiVP>=aUH%Y%h1{kC1D#$>fFX7Xt)PeDN01oDDC^r%Ir`B^0}jGrexdT<)dp zJA-VchyPtnOl+j##}8TTAg>_;noWuUe?DK`SxON#Bj^g^HKJDJM&Y-o8CZ2b-HSer za8+v~U}LURw=#_IeXbSSWb4bLnf{+TSA@g(rh^_1Vt;2DE9K5M3gQWuf2Z4S{T|8P zJN>}a?V1k|tzwgcoo^PuHIC|7A?C~g@8$z-h(N?fTG3eou`8JO^b%30!;YuB3tk=X zDR-AT!VlPZd(@7Eh{0`l{#3TyvaVm;203BlH>!1z@hSljEhLizDY<>t*uZ-4uDGRK zv-?y9F*N^g)uAB=C#Sx_V4SV=D^!S$ot<5E1opHKu9?gR06n=&=Rp;VJ6yjKu2S^d zNRW30X(=z;HwEm>YRmm)!K5H&RWBy%Q`OEF;d_McET_YOcXU8c$^of*4&)s7sVU`W z`g-0Mj*=lAZ|y{A#|9UNy;7Pi9i-#=4!paT0;uD_nbf!*MKMO!L-8kPuG4$QIVy^v zerm9%2F3!2l0k5d6%}he^Gp40s$$p#DLe#;D9*6 zI9rwGz&%^}kdr@WeT`OLjonw1tu)(Hm4T*f-8$jm+i|@i{1BoHyEMDnY|7q$Q_f=h zwnN<8vl`nHpP1K-yCzo`PQ(H$NaFDyi^^+-GB~a6nN58m3(HTH6I>s?-iU;3q^M z>5_+3Y;)eZ=x^Kaq+e)-;)!DAv-lMeur6zER70X<9)lk6mp%X18M^2{Wpi2c7g0?v zOl*QFZpE-j1`MQ$`&PD|zk*CQ*11n1wPNo6JqylA;SE*6nQUqT(68f%zD34l=f7Ky zJ$^WUi_Pv@jf-tK+)$z26bzlbOR4N4Mj~+Gm^t6&T*XbP3*%NSJJ7Rwt9ALkM>Qop z$UwP*zCSrj*eFey76&$;AJ?}{>^(iKcg)ea7AMZ7K~_1fjXA{ta>eQUz#oLrG_Qoz zbS_v#T=B(^np+oXcY;%mGpfh5y_h*8kIe24ucs!tdpq8yt#FCDNI_Zx9lh*FJL!RkWf-ay6;<#AAiyD^99 z7Y1RYEFU5SRv0JSaygYKRRcEH%DXUjSjHw? zMw7Wp{z*|QtBfHB-$M_isQ31V&GBMl1j4M54)P`gRrq=cD=ohm@qb*pW}=~|*?TtZ6f*W8DGG+@kQpDp5GjXuzwZTz4v{_G;C=Jq9~vh8wK^>9$O_1;D|d!;c5=O{OgnIc2M&Dby~>XS`IX3R{` zR%dX>1fx^UDD_y4d;QWUcYx|qf}MVMkmEk5)n}b^NW7n3{HOx96DK9<^oZP5X(*g} z{BT5#n>#L+3H#5Xob%x4<&f8UBEqCSHpweLLh&O!rk9%dy?^E$U zrw-|L+A12cAg?ENtn!AiaY%_@J~ie$92fXoede=SZ4k;w)xc5V5?StTznc&;{kdyB zByvdqO{hY=ZgAE*`o^@i-03tyZ9St)PKDcN8G&_I zMl5$)j03QrwD8WBgm@fmLx6i`La{f6)MgGk4WAh#23dkM&S@34C1p+B4YjxN;oh{! z{ua*w++Az>1792I^r)jLG(SL~ zAxa*LdA0*~&}$S=W1T8wYg6=WFzW51fs^SM7`e75F*3#p<6ab$*^{#@ddDf6c=f;h zxn#+%(3;Aui+*1&)Il!5(5Eat>F@6NuwR9z3$Cqe%Wrol8$zROFs=r4Loer)$sFrn zJ7pBU^IeH32FG-qR@7Ss8Z}RY9_eR7!rcw`^QzqjM_ROAv+_B2@PIpc-OT71Qndl@ z4X;;w&J3iV*ZfG~>PoX}@H#%6_3xD9rN0#62QRjthm{;Gi~g|UZ7O#yl{I{1w+jUXuR<^rAjZ47aNlhPU-b1nq^a+V^RQ~EJ0=m|Dy$v>$B{&+ zGbT>tY(@JsTd2{8u4f0%ug0r!asLA60PM}0x%je9q@F8y?lI3)*@N>$Q@l{gYIi|D zzFkb`>lNadf?pto=_s^|-^IFDH1_Pw)bwuOZP5(t-N4)T^BIHWQ1HKmWk92RQ9ouj zL_f5M^nL7%J{b@84*IDtxY8Supe0#uw4o~Kbcm8(Z#3cxTTDK#FDnCL-&cIkt@a6h zE&&2(@2l$9xDf}y%Obdn24}3+LXxrLoVM*dWd36H*1K(oU*iVnO#GY})!HtByq3(1 zR4rzl^=b|h5><;(x%sGZ5H3O;+|Thr`Xc{<-xHy1jQl9PUo*^5|65NFL#}prtTLnQ zhFCbuOBDxzW5}a;N-XcFV^26B^+Qp7tQV&+ZPSRl;LW?Zo;XTLL0m(p94B7LEP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3%f}~K~#8N?VZ`H zPG13X$YSks&wAmv$3Gby=U>6U zBk$%+m@px^e*JpVuV23`#c`bOhVRI`F`qtt3Rj=R9jANa6L~l0(W6JntXZ?NnBzFz z6`#nvF_$l2PUg;?o5g;>PMx#!ZQHhGDfLnQwzjr#_RRgC;OyD6$*^I=f(&!!%*j$~ z>1)=kX@3K8oT_8}yA+&}*JJPAy_}(kz&+f(d$&Dp_Uzdqt-J8?RSFW^F2g}f*LxcRU zUcCzaf?VS1)2HD%&;AwARX&AXgwhn`!_B5hp1+kNM~;NC{wH7@;jh?=c|!K$icItu zW3=ozEj1z;_!`K9hH#K7bXZw5L7*%5=!WhrUsEnO_nhEm9 zeFn&;1-UCwZ`s9Li&`^KUs!PZs%$KfKlTOm!Cuyv8i8L?mqorN`=}o}vv_xvJb4;H znY@0(SMz-McflA{A223bjs`Awz<0ixw?P1`QgNym|8`Iez?jNV|Xkev%qLlp#);F=NJrIAE{T z0Xx{{`Sa&V>Nv^NsZ+C*=5p)Stz`cE`B|(6M-RJq?@ksjT$rVFo&yICB!>?l&SHOt zqeqV>J9g~&$@lQbmoHx?_wL=xQvOb^UcH(;e*8EYIdWu{QUiU`G1FH zyLZ9YWFLHv_}jN{L%f;f$x{z}^5DUP$+&UjvXmd}+O;c;#b!VsfW{-^yA`1CvSrJX zOP4OSx6NGh<;$0F&+}8KPKDpLMvop{UjN#BUJSbfvf15_b`Gsr;ai1vEoF8?td{k5 zwXC+Rsus$$@-LT7f1vS}Hx4SB8Ih!d>up+h~t z(`#ux%Iv(51N|j~c81g~Ik5$K;{L{l4`kykRQyba{XpSX{G1RK&fJVS2s*|tcF z?LphNp1kpj?2-}r?K9dSP0y^aTipn;t*ty%-)yJ;_E}@{Kb6 zVnHVDg7f+WXj^_skR7OBGH{O^+{b;F2R0$UC2u~7^E9I2C_`B(5(jJKzkxg%<4^>h zkT=Q2$oceI6eCB?3wE$Hn|Kli9M%phffJz@`qSU!Ll28htueznOJkd*+mOSyWwNge|AB8Tb*+Kk7U zZBI~V?8DSUS?Z>J?$t)zFM2N7Et1>Xk-Dv%fUfc}>YufZ&(kA@ekWfXY`=Gf zhNFyzF^&bL@+OKZgFbnk9-|H`0!NK)qfW_r^vr^OMQt$P)ISXJyz+uPny_N1-%iA~&3J539$9T4kyn$b zB`=>Hd-3Fk{IRcTB37V3ktv?E2vt|qNMzR2Bel}0)q#@m=@mHorj2JN@TwlL_9rU43>^Y*XhoEO=;T)3w0s5$C z&z|8v5BwfEh7TW}JbU&mORaI^#*JjlmMvMVcD~xDPoHpq;lhPv<;s=e9{83&?t98l zo;*2=)!!*ImlZP^P{vf~g&Ac+e9AnGj z)9Iqo!H)EiJzGbw_3PJXv08lQ%$Zs22gi;b>tNR+=o5UOd2HIWX<2I5kuB|SBd1TF z4*jm*MHthxhwZuQEWaUXhZmyN-L8T_8Y{VAwNHh~Vl`N4?5?F1AXlSM1kcL6-W0vA ziM$;xD}CM$`B%{{3)@?nkTDNrDC!gHVwZv);{NU`+HG_O>_<8D>53ebE81D1A3n`< z^u-pkVG-=;?2b`mLQvlJInR(^&{p2gG6uPA-^BUic7VELU!x9N4{cj}bf!<@x+rJI zJ#8bCY#7T!I%U+4*pj%lIc4(36Zz~em3(##Q73t1>$qRyw--^Aj-J*|svp^?JGNV% z9j!ch#ARqB?o;B@8-455XQ{g*KY#vwxc2VdJ6s`NA=s@<}e@&j0D+uGW~ z%0jv=XaBf_FA#v$iq(%ap6Sa2{%D0X;_N=TFCx{aVJIT)#N_13lkKY}@*;-?UD;6- zL7C5=KPSC<^~zFy?0}kqc3C@j?o9UV*%R7g7s(2r2fu>TPcf9+zI}VLYSpT+>$!OG zV(1s@YBhWTbm-8baBp{CWnp)m_XPy-wT*T@*p4p(WJ3#nR-`*SUchFAwQJV~d+RMG z9f-mAd4`{J9Xxn&XbT_a8Tm=a#`1r5pkv35ZO^B-1@4jM#EBEZw+0Rz7{&zU@hclA zoI7_e)Far{TK^j`U_iL)Ekol9Xa_y0Cl7psKQaT#G1fP4-rR1(Se_RzUW9b!55|Vx zhCqLeMj4*dw&b90P+dTuvID1H@}?7S7_)jSqhF9u@bwHkTJ)5Sfj1DwOAI#Sizn)* z%?}?wg!C0FRs=cdH;`?Vti?>JfA*cr0=a<5f~6^{B?jqDDQysCrxC_^6P;GRHT+OP!=ypW``cw5f4q`-(P*OFk>NY(RUeL(s>P zfilWVz0|2XcxL^ad+fn8uCb5A@@Tx0Mqc9FlNRf3?JOISruL;jd3hGwUHu}ci@f9$ zs@Iki(v9czm2HnJamfkfBQCpgm2CCUc#~|gEXd7st4kR=H_8f#I~)*HLZZCxr36X~T_`RLj|5lh2 zng5D5WO@9SiCmMmR%jeu1ByY(3e4ofz48(;Drw{=50H<+qScwWo;k%}PwZwF#5~A{ zJ+(vpTR<+Hx85RD56Yo?GZ%c?z<-@;!uaT_e>EHY-)=%WJCXmEe>5u{K;hSYef7b4 z(u^51!u_{z-@>^p=Tw||rmJGozkmO5uFfyVq;U?!IUDES3l=O0XPNWn%?sr@`^x)O z+vy1QPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2jfXZK~#8N?VP)7 z7EKg~Ctoi??L>m8ja9%)CxR9#l3xFVU{VWWN)zx_S$HV~JGBx*B5DyqMN%jzC^kt7 zO&L-Dg7`k;{^H4bXZQ8PTwFO147)QsbLQM;cHiBQzU2-n2!ht~Uv&(Eprynj4uX~w zi#P~cPAuXeXgRTngP`TaA`XI<6N@+qTEdkpSJKOuFRR)wetQu!xUa7-?cKY#YS|c0 zo;;c7y?_6H)e`h#VPPTrjPm8nm#Q_bw5e>{wk?f~ja66Ik2-z+R&L+Eokm7Rs@lf! z?%lhUd}p0e7w9uEFpxfc_|P3Q{@BAaJw3gA;>3xn_KOP_E-artd$y`=3`COB1 z@6(|}hpO67K7an4I*E|w!QsP)bN$n&Pr1IHl=Nw$DGw(mCf4oAj2HmEvG6ppo^Yo< zfBt+L9v;qh?z-Q;eaq)??b@|;?%cU_^yty%JF#|rTkM^eoq`>K-H~hBH5f;muCudq zZg)}b#EfG{v3C`A9r|;PBXz+X?7Wi6SlvlB1MENt`A0h=I#TC4w$TTDsSA8VfB68L z7zY|}3;pp0=l%(ZJA(X)pXq1kqRro7ncK=yylp>pmyYOfuQkQV+D4IG!s^43@$wxo zFXPauDGya=K0$xxlWxqV9QmENSkOs%Ei_JZQ)D}~=o&}qg}&-1zfq9oVGP%#GoZI! zKY*O#6GC-d1(W;9WC+U1X_|y{6d|d&j$t@Sj#tp60R7|y!v4}US2O(yKNi7oIKa|roNdT@=pO#WDHpWeHVqV5I*(QA`$VCsy2IjQ7fSpeu6F*vz!&qc9Kj)gm$3@p|jtS{) z{V0ev*KBT}Gx3tm=w;=i7j2B85A{-fk%Mesw0?TgwTPLJfOwdQb{QzgSeV#5hyIL{ zAvjibkmHm%9{Sp3p)X@L3%d|KK1k@TMCIHjU&$8wmi$oaXMOJz8{gVGXc4N&uhtIa z%Gb!W$=(zvZyVULC4IPNZNP8jl&H%?KaPIhKgf~afpcH4v%}}K&^#RLu>J#I=iKTc zd_So3b&0M;jIh#f;hjv7w5x-R^vO*!&`u#J$nlP#PLPpl$1CyF=95(mfr1R1sD1}u zD@YccjxBx;KQ9R(U;5qO+X5xMW6(+N3O~5-cQiAi2cNZpvwRS$p(@nDJfW|cnN}L1LtKD7#kcQIjp{nFX=CkCx_RS zx)rS$B!TL5%{JC&z?O?$BrG#=N8_w z&CSiNd>`bkqQ1c~$C)!{YQG(NnQz{_$+{s!ZwsG3eVRIs$>+e^U0e4&e*Bn-HWvS8 zQs9rex0JK9v-yZEl+n@A{N@+?pc9Dn>eZ`!jgR&mckSAhZQ&a{*XU0>K9yf*W@gg< z{rgw?ZP~IVw{wmzckbNDvDvwEXMStRcw%Vllm`zUWI5uf@)iGH zaq1*pnwpx*=Zw>vR=oxH`Y3;hC2xa?v(TH@QXV23Bnx#sZ-e|bol=Ld+rCm&Uwj)=u7+o-*q;k zbn)WFT=(#1zAHaFNxKSGI?eXB%}&YgAlU8L9ca_;N!{+o7Iqb6QaINR%`nLA^fctTy^m=bScgxAn7pM4RT9 z{q*IU_q*aEkVRkm3CXqNN=PT>qpzMgD4g4v>gj@lt`ya|X0iVBz6Eq<4r_;{)&JRp zos?aiT@g4wfBrn(xN#%bHxmB(X>xM1_AVa$y>M6OX=XF>=6B%^&eI*=iS;d6wEAzS zA3l7z>Jjno-Mjzm4{=Lq11wzql+aI;60Kdt{FdT()1^z7a-H9q z)URH>n(G^he&gBSSV24B>87ItYST z#6i${Vi5;H%ZWuC1T7~PaS*heSj0ila$*q&L90pW2LTCtGL{-I-T(jq07*qoM6N<$ Ef|7PZL;wH) literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_7.png b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/aatsr/images/eq003_searchPath_7.png new file mode 100644 index 0000000000000000000000000000000000000000..608a052df44ee7a009275280c83ba26cd1535c86 GIT binary patch literal 2624 zcmb7GYdjMQ8=r&FVv0jyDN?Gr)!~(e=9=4xnA@nSs9bW{+%}HM5we}AXy%ejH#O!O zHgX~w*@(ta$(;?$h}n3ZPw(gV!*lun|G($|;ra0Vo(wm*z5HIay#N3}-r=H+I{+Zz zyW4BY?%B<33FDL77STugeI8CnA=~?TbV;Tkpjm zk@cM{UN|d@KN6DR9g?~WkE?Kw$l@Poq?yR#ORl4y%I``~{(nh0(_dzP6NM^0B^_OO zaJk<|V3j!4{owq;=kUT;x9pgPI5IR=ztOf!H=jge2pd92+=uSVV2jD*UfiV8eeHFZ zkTX%-k=p04T*l1^O?|ICD{G2lm&RV+!e4cR?`KDrV#R`a56`n!8xaT6udmL0`rH`t zjpE2Nbk?k+M^4&#suks)aGeSAXQ^6XH-BCi?wV~XPTr%(ZLA#Kskq@OlwN=1-*jg5 zM75j`rx(4V9{6S_taST)2e!Y|*7IiE!iSc?{OBoLgKlsE6EA$94nkD$FNjE7v4`Ey zq4q3Qg8`E9?N{zlR#!vV=&OM%SkZ-m8t+)a+hXTyfn9ooz@+&XSxqg$3d37?OEsD~qk=Y~h#MpsHA2YON< zCUa`nEvQPkb^V@S=*^$gp~N(^O#-BNeW{`^5Oa%x>9T`gA2+&^D7PeA?vY+`a^2rL zJzMVz)W~*EF|}*UzjR4K2E0unZJ$h7&cwc&!AOFJU5^CAR2TUt zE!G=XA{o#5l0w64iSZJs>cPWwj2kwPJlYx(fy<-KO;?3BiXFVJ6u20I5?)(AcIQ6O z8$q=vE!Ngw%IzT#S;jyIXXO0cGyuP||JzGdMu1KaAh20iTYJux zEzN!qAm3-dU`BB#w{gF)Mpmxu5AtlRP z@vNXUH?;|Jjx}a;BFT8uLN=RZC@Z;uzX;$Olideo7a_xU-BA6YkUMB_$g(OB*be*9 zuwUx)aiYt;=GGYc6f~7_lq9N%_*f?6bDL;x0P_peDta~?)bahN@+&N7vZcjdgqnI_ zx6YzAj^kev8tr1Xz(Ozf9NE~u8y8x_7MRCILjISbn(3wlCB|y3{zU^lxM9W_9G}&RLD>E`qPF}xo$a? zsV3V?w%&dcJ_Q1cFBedwK+59WuDH$P&=YZ7A3UCE~XV%x`oTxd#f zGrZWMkf{ps{u`~;c4y+Bn4N7gB&!cm6(IhSE-kJ*%@@pn9+bm+k~VcTpsY?P(FJ#v zy*kUReItkz3)dh{^smUUp9p?S{OXM)zbhYebmq5yE&D9>J~`|2j1bH$nr03d{HhpM za#}EkWAy`DY3hC{#U+^a!Yfm8dDZ&QR8aQ}cKxbu-AF>WCjJWdB&B$R&0=)HmPxd& zA}wKK_&7;H!}RY(Zp*uk4rtThq_&xarLKo7bjSq`zY)mlui}YOtD18}s?rqk-_^FZ z)8bca=u-zGfG-qS*7qp^bkbx?%=`c(3og`-IA>oa*uRQi{DPh~3FACW=Fe&%3vG`w zrKb<@Sab}J<3ICBuDZ!wR^24@qN+iF^YXVg=JZe{B6w@A4<`o^nsy4RSRnErSt$sw>!J4 zZLVBC>NlS@zsK(|KQ5OlCw8iAIZ~xLS3wP0sjtBvofl%2Rgg;L=n^MggeiA?KaK%^ zXVRG#tsX7tS7jed9j_T-d{^h8v-2N?YVHZmbtU_?%@GrzOY|ui-(dPr&Mp6p=O}<$ z>_TYqeQmVb?fOTMgfP*eXpU^CP2Ws|<}$2ZMf5tgl~q*_AaSh-CSO#YklgE8^y6Ti zLVa1mhGk(~UC>0eVN)IJZ-H5G>B$FF z#9CdW`d=zuD{OqfA=e6;cf=q}AvaN*>+;<3&F%~(e=a0$*UdwQ7v8aFn=z$`&76VHdGmgsTW#_vSs=erRyN}|s< zm8D>cbv9VEq7;mEhRWKri<}{KFhwanC1BVt+0$XA{y)jlap$*Md)RBn@i@Wm*9UO0 Lh1*c9uHgR*a#=L9 literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/help.hs b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/help.hs new file mode 100644 index 00000000..6b261657 --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/help.hs @@ -0,0 +1,24 @@ + + + + + IdePix AATSR Help + + top + + + + TOC + + javax.help.TOCView + toc.xml + + + Search + + javax.help.SearchView + JavaHelpSearch + + diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/images/snap_header.jpg b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/images/snap_header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d034251ee9b1547ba5c56e47fb4e22f7a00a70ea GIT binary patch literal 21069 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 literal 0 HcmV?d00001 diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/map.jhm b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/map.jhm new file mode 100644 index 00000000..05fa8c97 --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/map.jhm @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/style.css b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/style.css new file mode 100644 index 00000000..6f023170 --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/style.css @@ -0,0 +1,181 @@ +body { + background-color: #FFFFFF; + color: #000000; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12; + padding: 6pt; + margin: 6pt; +} + +p { + font-family: Verdana, Arial, Helvetica, sans-serif; + margin: 6pt; +} + +.i1 { + margin-left: 30; +} + +.i2 { + margin-left: 50; +} + +.note { + font-family: Verdana, Arial, Helvetica, sans-serif; + color: red; +} + +.inote { + font-family: Verdana, Arial, Helvetica, sans-serif; + background-color: #DDDDDD; +} + +.code { + color: blue; + font-family: courier new, courier, Monospaced, cursive; + text-align: left; + font-weight: normal; + text-decoration: none; + font-style: normal; +} + +h1 { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 25; + font-weight: bold; + margin-top: 18pt; + margin-right: 6pt; + margin-bottom: 12pt; + margin-left: 6pt; +} + +h2 { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 21; + font-weight: bold; + margin-top: 18pt; + margin-right: 6pt; + margin-bottom: 12pt; + margin-left: 6pt; +} + +h3 { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 18; + font-weight: bold; + margin-top: 18pt; + margin-right: 6pt; + margin-bottom: 12pt; + margin-left: 6pt; +} + +h4 { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 15; + font-weight: bold; + margin-top: 18pt; + margin-right: 6pt; + margin-bottom: 6pt; + margin-left: 6pt; +} + +h5 { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12; + font-weight: bold; + margin-top: 18pt; + margin-right: 6pt; + margin-bottom: 6pt; + margin-left: 6pt; +} + +h6 { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11; + font-weight: bold; + margin-top: 18pt; + margin-right: 6pt; + margin-bottom: 6pt; + margin-left: 6pt; +} + +li { + margin-top: 4pt; + margin-bottom: 4pt; +} + +table { + border-width: 0; + border-collapse: collapse; + padding: 1px; + margin: 0; +} + +invisibletable { + border-width: 0; + border-style: solid; + border-color: #FFFFFF; + border-collapse: collapse; + padding: 1px; + margin: 0; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + font-style: normal; +} + +th { + font-size: 12; + text-align: left; + border-width: 1; + border-color: #BBBBBB; + border-style: solid; + border-collapse: collapse; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + padding-bottom: 3px; +} + +td { + font-size: 11; + border-width: 1; + border-color: #BBBBBB; + border-style: solid; + border-collapse: collapse; + border-spacing: 0; + padding: 0; + padding-left: 6px; + padding-right: 6px; + vertical-align: top; +} + +table.header { + width: 100%; + height: 29; + font-size: 17; + color: #ffffff; + vertical-align: middle; + background-color: #274351; + border-width: 0; + padding: 0; + margin: 0; +} + +.header { + font-size: 17; + height: 29; + color: #ffffff; + vertical-align: middle; + background-color: #274351; + border-width: 0; + padding: 0; + white-space: nowrap; +} + +hr { + height: 4; + color: #000063; + border-color: #000063; + border-style: solid; + border-width: 1; +} diff --git a/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/toc.xml b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/toc.xml new file mode 100644 index 00000000..fd6596d2 --- /dev/null +++ b/idepix-aatsr/src/main/javahelp/org/esa/snap/idepix/aatsr/docs/toc.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/idepix-aatsr/src/main/nbm/manifest.mf b/idepix-aatsr/src/main/nbm/manifest.mf new file mode 100644 index 00000000..1d767356 --- /dev/null +++ b/idepix-aatsr/src/main/nbm/manifest.mf @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +AutoUpdate-Essential-Module: false +OpenIDE-Module-Java-Dependencies: Java > 1.8 +OpenIDE-Module-Display-Category: SNAP Supported Plugins +OpenIDE-Module-Long-Description:

Classification of pixels (cloud, snow, ice, land, water) originating from AATSR 4th reprocessing data

+

Vendor: Brockmann Consult GmbH

+

Release notes: Release notes on GitHub +

Contact address: Chrysanderstr. 1, 21029 Hamburg (Germany)

+

Copyright: (C) 2022 by Brockmann Consult GmbH

+

Vendor: Brockmann Consult GmbH

+

License: GPLv3

+OpenIDE-Module-Layer: layer.xml + diff --git a/idepix-aatsr/src/main/resources/META-INF/services/org.esa.snap.core.gpf.OperatorSpi b/idepix-aatsr/src/main/resources/META-INF/services/org.esa.snap.core.gpf.OperatorSpi new file mode 100644 index 00000000..aa028b2c --- /dev/null +++ b/idepix-aatsr/src/main/resources/META-INF/services/org.esa.snap.core.gpf.OperatorSpi @@ -0,0 +1 @@ +org.esa.snap.idepix.aatsr.IdepixAatsrOp$Spi diff --git a/idepix-aatsr/src/main/resources/helpset.xml b/idepix-aatsr/src/main/resources/helpset.xml new file mode 100644 index 00000000..b5e1b35c --- /dev/null +++ b/idepix-aatsr/src/main/resources/helpset.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/idepix-aatsr/src/main/resources/layer.xml b/idepix-aatsr/src/main/resources/layer.xml new file mode 100644 index 00000000..938eb6dc --- /dev/null +++ b/idepix-aatsr/src/main/resources/layer.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/IdepixAatsrOpTest.java b/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/IdepixAatsrOpTest.java new file mode 100644 index 00000000..7d095b06 --- /dev/null +++ b/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/IdepixAatsrOpTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2022 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see http://www.gnu.org/licenses/ + */ + +package org.esa.snap.idepix.aatsr; + +import org.esa.snap.core.datamodel.Mask; +import org.esa.snap.core.datamodel.Product; +import org.esa.snap.core.datamodel.ProductData; +import org.esa.snap.core.gpf.GPF; +import org.esa.snap.core.gpf.OperatorException; +import org.esa.snap.core.gpf.OperatorSpi; +import org.esa.snap.core.gpf.OperatorSpiRegistry; +import org.esa.snap.core.util.DummyProductBuilder; +import org.esa.snap.core.util.math.Range; +import org.junit.Test; + +import java.awt.Color; +import java.awt.Rectangle; +import java.util.List; + +import static org.junit.Assert.*; + +public class IdepixAatsrOpTest { + + @Test + public void testOperatorSpiIsLoaded() { + OperatorSpiRegistry registry = GPF.getDefaultInstance().getOperatorSpiRegistry(); + OperatorSpi operatorSpi = registry.getOperatorSpi("Idepix.Aatsr"); + assertNotNull(operatorSpi); + assertEquals("Idepix.Aatsr", operatorSpi.getOperatorAlias()); + assertNotNull(operatorSpi.getOperatorDescriptor()); + assertSame(operatorSpi.getOperatorClass(), operatorSpi.getOperatorDescriptor().getOperatorClass()); + } + + @Test + public void testTargetProductSignature() { + final Product aatsr = createDummyAatsrSource(); + final IdepixAatsrOp idepixAatsrOp = new IdepixAatsrOp(); + idepixAatsrOp.setSourceProduct(aatsr); + + idepixAatsrOp.setParameterDefaultValues(); + + final Product targetProduct = idepixAatsrOp.getTargetProduct(); + assertEquals(aatsr.getName() + "_idepix", targetProduct.getName()); + assertEquals("AATSR_IDEPIX", targetProduct.getProductType()); + assertEquals(aatsr.getSceneRasterSize(), targetProduct.getSceneRasterSize()); + + } + + @Test + public void arangeTest() { + double[] expected = {-22.5, -21.5, -20.5, -19.5, -18.5, -17.5, -16.5, -15.5, -14.5, -13.5, -12.5, -11.5, -10.5, -9.5, -8.5, -7.5, -6.5, -5.5, -4.5, -3.5, -2.5, -1.5, -0.5}; + final double[] arange = IdepixAatsrOp.arange(-22.5, 0.5, 1); + assertArrayEquals(expected, arange, 1.0e-6); + } + + @Test + public void validate_ValidSourceProduct() { + final Product aatsr = createDummyAatsrSource(); + + try { + final IdepixAatsrOp idepixAatsrOp = new IdepixAatsrOp(); + idepixAatsrOp.validate(aatsr); + } catch (Throwable t) { + fail("No exception expected here! Source should be valid."); + } + + } + + @Test(expected = OperatorException.class) + public void validate_InvalidSourceProduct_WrongType() { + final Product aatsr = createDummyAatsrSource(); + aatsr.setProductType("differentType"); + + final IdepixAatsrOp idepixAatsrOp = new IdepixAatsrOp(); + idepixAatsrOp.validate(aatsr); + } + + @Test(expected = OperatorException.class) + public void validate_InvalidSourceProduct_MissingBand() { + final Product aatsr = createDummyAatsrSource(); + aatsr.removeBand(aatsr.getBand("cloud_in")); + + final IdepixAatsrOp idepixAatsrOp = new IdepixAatsrOp(); + idepixAatsrOp.validate(aatsr); + } + + @Test + public void detectFirstLastMaskedPixel() { + final Product aatsr = createDummyAatsrSource(); + // Col 0 = 25-30 + // Col 560 = 10-12 + // Col 1300 = 300-400 + final Mask testMask = Mask.BandMathsType.create("TEST_MASK", "", aatsr.getSceneRasterWidth(), aatsr.getSceneRasterHeight(), + "(X==0.5 && Y>=25.5 && Y<=30.5) ||" + + "(X==560.5 && Y>=10.5 && Y<=12.5) ||" + + "(X==1300.5 && Y>=300.5 && Y<=400.5)", + Color.yellow, 0.5f); + + + aatsr.addMask(testMask); + int[] range; + range = IdepixAatsrOp.detectMaskedPixelRangeInColumn(testMask, 0); + assertEquals(25, range[0], 1.0e-6); + assertEquals(30, range[1], 1.0e-6); + + range = IdepixAatsrOp.detectMaskedPixelRangeInColumn(testMask, 560); + assertEquals(10, range[0], 1.0e-6); + assertEquals(12, range[1], 1.0e-6); + + range = IdepixAatsrOp.detectMaskedPixelRangeInColumn(testMask, 1300); + assertEquals(300, range[0], 1.0e-6); + assertEquals(400, range[1], 1.0e-6); + + } + + @Test + public void sliceRectangle_atZero() { + final List rectangles = + IdepixAatsrOp.sliceRect(new Rectangle(0, 0, 512, 43138), 2000); + + assertEquals(22, rectangles.size()); + assertEquals(new Rectangle(0, 6000, 512, 2000), rectangles.get(3)); + assertEquals(new Rectangle(0, 42000, 512, 1138), rectangles.get(21)); + } + + @Test + public void sliceRectangle_withYOffset() { + final List rectangles = + IdepixAatsrOp.sliceRect(new Rectangle(0, 12356, 512, 20222), 2000); + + assertEquals(11, rectangles.size()); + assertEquals(new Rectangle(0, 12356, 512, 2000), rectangles.get(0)); + assertEquals(new Rectangle(0, 18356, 512, 2000), rectangles.get(3)); + assertEquals(new Rectangle(0, 32356, 512, 222), rectangles.get(10)); + } + + @Test + public void createDistanceArray() { + final int[] distanceArray = IdepixAatsrOp.createDistanceArray(25, 1000); + assertEquals(51, distanceArray.length); + assertEquals(-25000, distanceArray[0]); + assertEquals(-24000, distanceArray[1]); + assertEquals(-23000, distanceArray[2]); + assertEquals(24000, distanceArray[distanceArray.length - 2]); + assertEquals(25000, distanceArray[distanceArray.length - 1]); + } + + @Test + public void calcPathAndTheoreticalHeight() { + // input values taken from Python + float maxObjAlt = 6000; + float minSurfAlt = -65; + double orientation = 154.91488; + float oza = 16.4364f; + float saa = 313.2662f; + float spatialRes = 1000; + float sza = 83.9982f; + float x_tx = 173500.0f; + + // expected values taken from Python + double[] illuPathHeight = {-40.56836, 53.990723, 148.30078, 186.63232, 281.31152, 375.73584, 469.8916, 413.7661, 508.5747, 603.1211, 697.3926, 735.772, 830.4507, 924.84717, 1018.9448, 962.89453, 1057.7168, 1152.2485, 1246.4727, 1284.9097, 1379.5894, 1473.9512, 1512.0195, 1606.8594, 1701.3726, 1795.5366, 1834.0474, 1928.7266, 2023.0447, 2061.1404, 2156.0017, 2250.4902, 2344.5764, 2288.1187, 2383.1836, 2477.8623, 2572.122, 2610.2534, 2705.1443, 2799.6, 2893.5803, 2837.186, 2932.3176, 3026.9954, 3121.175, 3159.3547, 3254.2874, 3348.6963, 3386.2214, 3481.4473, 3576.1243, 3670.1855, 3708.437, 3803.4297, 3897.7683, 3935.1997, 4030.5703, 4125.245, 4219.1143, 4161.652, 4257.481, 4352.5723, 4446.79, 4484.059, 4579.6772, 4674.348, 4767.853, 4710.1294, 4806.434, 4901.715, 4995.68, 5032.597, 5128.74, 5223.395, 5257.624, 5355.065, 5450.8574, 5543.962, 5579.5537, 5677.532, 5771.981, 5796.0537, 5898.027, 6000.0}; + int[][] illuPathSteps = {{-22, -55}, {-22, -54}, {-22, -53}, {-21, -53}, {-21, -52}, {-21, -51}, {-21, -50}, {-20, -51}, {-20, -50}, {-20, -49}, {-20, -48}, {-19, -48}, {-19, -47}, {-19, -46}, {-19, -45}, {-18, -46}, {-18, -45}, {-18, -44}, {-18, -43}, {-17, -43}, {-17, -42}, {-17, -41}, {-16, -41}, {-16, -40}, {-16, -39}, {-16, -38}, {-15, -38}, {-15, -37}, {-15, -36}, {-14, -36}, {-14, -35}, {-14, -34}, {-14, -33}, {-13, -34}, {-13, -33}, {-13, -32}, {-13, -31}, {-12, -31}, {-12, -30}, {-12, -29}, {-12, -28}, {-11, -29}, {-11, -28}, {-11, -27}, {-11, -26}, {-10, -26}, {-10, -25}, {-10, -24}, {-9, -24}, {-9, -23}, {-9, -22}, {-9, -21}, {-8, -21}, {-8, -20}, {-8, -19}, {-7, -19}, {-7, -18}, {-7, -17}, {-7, -16}, {-6, -17}, {-6, -16}, {-6, -15}, {-6, -14}, {-5, -14}, {-5, -13}, {-5, -12}, {-5, -11}, {-4, -12}, {-4, -11}, {-4, -10}, {-4, -9}, {-3, -9}, {-3, -8}, {-3, -7}, {-2, -7}, {-2, -6}, {-2, -5}, {-2, -4}, {-1, -4}, {-1, -3}, {-1, -2}, {0, -2}, {0, -1}, {0, 0}}; + double thresHeight = 101.97246511092132; + + final IdepixAatsrOp.PathAndHeightInfo pathAndHeightInfo = IdepixAatsrOp.calcPathAndTheoreticalHeight(sza, saa, oza, x_tx, orientation, (int) spatialRes, (int) maxObjAlt, minSurfAlt); + + assertArrayEquals(illuPathHeight, pathAndHeightInfo.illuPathHeight, 1.0e-2); + for (int i = 0; i < illuPathSteps.length; i++) { + int[] illuPathStep = illuPathSteps[i]; + assertArrayEquals(illuPathStep, pathAndHeightInfo.illuPathSteps[i]); + } + assertEquals(thresHeight, pathAndHeightInfo.threshHeight, 1.0e-2); + } + + private Product createDummyAatsrSource() { + final DummyProductBuilder pb = new DummyProductBuilder(); + pb.size(DummyProductBuilder.Size.MEDIUM); + pb.gc(DummyProductBuilder.GC.PER_PIXEL); + final Product product = pb.create(); + product.setProductType("ENV_AT_1_RBT"); + product.addBand("solar_zenith_tn", ProductData.TYPE_FLOAT32); + product.addBand("solar_azimuth_tn", ProductData.TYPE_FLOAT32); + product.addBand("sat_zenith_tn", ProductData.TYPE_FLOAT32); + product.addBand("confidence_in", ProductData.TYPE_FLOAT32); + product.addBand("elevation_in", ProductData.TYPE_FLOAT32); + product.addBand("cloud_in", ProductData.TYPE_FLOAT32); + product.addBand("latitude_tx", ProductData.TYPE_FLOAT32); + product.addBand("longitude_tx", ProductData.TYPE_FLOAT32); + product.addBand("x_tx", ProductData.TYPE_FLOAT32); + return product; + } + +} diff --git a/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/OrientationOpImageTest.java b/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/OrientationOpImageTest.java new file mode 100644 index 00000000..7e900704 --- /dev/null +++ b/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/OrientationOpImageTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022. Brockmann Consult GmbH (info@brockmann-consult.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see http://www.gnu.org/licenses/ + * + */ + +package org.esa.snap.idepix.aatsr; + +import org.esa.snap.core.datamodel.ProductData; +import org.esa.snap.core.util.ImageUtils; +import org.junit.Test; + +import java.awt.image.RenderedImage; + +import static org.junit.Assert.assertEquals; + +/** + * @author Marco Peters + */ +public class OrientationOpImageTest { + + + @Test + public void testOrientationImage() { + float[] lats = { + 56.0214f, 55.7504f, 55.4608f, 56.0214f, + 55.1538f, 55.7504f, 55.4608f, 55.1538f, + 57.3770f, 57.3770f, 57.1410f, 56.8849f, + 57.1410f, 56.6093f, 56.3146f, 56.8849f, + }; + float[] lons = { + -175.4993f, -177.0226f, -178.5242f, -175.4993f, + +179.9959f, -177.0226f, -178.5242f, -179.9959f, + -172.8034f, -174.4020f, -175.9795f, -174.4020f, + -177.5348f, -179.0667f, -175.9795f, +179.4245f + }; + + final RenderedImage latImage = ImageUtils.createRenderedImage(4, 4, ProductData.createInstance(lats)); + final RenderedImage lonImage = ImageUtils.createRenderedImage(4, 4, ProductData.createInstance(lons)); + final OrientationOpImage orientation = new OrientationOpImage(latImage, lonImage); + assertEquals(4, orientation.getWidth()); + assertEquals(4, orientation.getHeight()); + + assertEquals(+162.342737, orientation.getData().getSampleDouble(0,0,0), 1.0e-6); + assertEquals(-179.914133, orientation.getData().getSampleDouble(1,1,0), 1.0e-6); + assertEquals(90.0, orientation.getData().getSampleDouble(2,2,0), 1.0e-6); + assertEquals(-0.165765, orientation.getData().getSampleDouble(3,3,0), 1.0e-6); + } + + @Test + public void computeOrientation() { + assertEquals(-45.004363, OrientationOpImage.computeOrientation(1, 2, 2, 3f), 1.0e-6); + assertEquals(-26.917511, OrientationOpImage.computeOrientation(10f, 10f, 11f, 12f), 1.0e-6); + } + +} \ No newline at end of file diff --git a/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/RunOpMain.java b/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/RunOpMain.java new file mode 100644 index 00000000..eedc5d42 --- /dev/null +++ b/idepix-aatsr/src/test/java/org/esa/snap/idepix/aatsr/RunOpMain.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022. Brockmann Consult GmbH (info@brockmann-consult.de) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see http://www.gnu.org/licenses/ + * + */ + +package org.esa.snap.idepix.aatsr; + +import org.esa.snap.core.dataio.ProductIO; +import org.esa.snap.core.datamodel.Product; +import org.esa.snap.core.gpf.GPF; +import org.esa.snap.core.util.SystemUtils; + +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.logging.Level; + +/** + * @author Marco Peters + */ +public class RunOpMain { + + public static void main(String[] args) throws IOException { + SystemUtils.init3rdPartyLibs(RunOpMain.class); +// final Product aatsr = ProductIO.readProduct("H:/SENTINEL3/AATSR4RP/v2.0.5/ENV_AT_1_RBT____20021129T235200_20021130T013735_20210315T024827_6334_011_359______DSI_R_NT_004.SEN3/xfdumanifest.xml"); +// final Product aatsr = ProductIO.readProduct("H:\\related\\QA4EO\\AATSR4th Cloud Shadow\\ENV_AT_1_RBT____20020810T083508_20020810T102042_20210303T040313_6334_008_264______DSI_R_NT_004.dim"); + final Product aatsr = ProductIO.readProduct("H:\\related\\QA4EO\\AATSR4th Cloud Shadow\\ENV_AT_1_RBT____20090615T133401_20090615T151936_20210625T140648_6334_079_496______DSI_R_NT_004.SEN3"); + + Instant start = Instant.now(); + + final HashMap parameters = new HashMap<>(); + parameters.put("copySourceBands", false); + parameters.put("cloudTopHeight", 6000); + final Product shadowProduct = GPF.createProduct("Idepix.Aatsr", parameters, aatsr); + ProductIO.writeProduct(shadowProduct, "H:\\related\\QA4EO\\AATSR4th Cloud Shadow\\" + aatsr.getName() + "_shadowOnly.dim", "BEAM-DIMAP"); + Instant stop = Instant.now(); + SystemUtils.LOG.log(Level.INFO, "DURATION: " + Duration.between(start, stop)); + } +} diff --git a/pom.xml b/pom.xml index 83665b3a..45ccb6d0 100644 --- a/pom.xml +++ b/pom.xml @@ -35,8 +35,10 @@ + idepix-core + idepix-landsat8 idepix-meris