def test_testArithmetic(self): # Test of basic arithmetic. (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d a2d = array([[1, 2], [0, 4]]) a2dm = masked_array(a2d, [[0, 0], [1, 0]]) assert_(eq(a2d * a2d, a2d * a2dm)) assert_(eq(a2d + a2d, a2d + a2dm)) assert_(eq(a2d - a2d, a2d - a2dm)) for s in [(12,), (4, 3), (2, 6)]: x = x.reshape(s) y = y.reshape(s) xm = xm.reshape(s) ym = ym.reshape(s) xf = xf.reshape(s) assert_(eq(-x, -xm)) assert_(eq(x + y, xm + ym)) assert_(eq(x - y, xm - ym)) assert_(eq(x * y, xm * ym)) with np.errstate(divide='ignore', invalid='ignore'): assert_(eq(x / y, xm / ym)) assert_(eq(a10 + y, a10 + ym)) assert_(eq(a10 - y, a10 - ym)) assert_(eq(a10 * y, a10 * ym)) with np.errstate(divide='ignore', invalid='ignore'): assert_(eq(a10 / y, a10 / ym)) assert_(eq(x + a10, xm + a10)) assert_(eq(x - a10, xm - a10)) assert_(eq(x * a10, xm * a10)) assert_(eq(x / a10, xm / a10)) assert_(eq(x ** 2, xm ** 2)) assert_(eq(abs(x) ** 2.5, abs(xm) ** 2.5)) assert_(eq(x ** y, xm ** ym)) assert_(eq(np.add(x, y), add(xm, ym))) assert_(eq(np.subtract(x, y), subtract(xm, ym))) assert_(eq(np.multiply(x, y), multiply(xm, ym))) with np.errstate(divide='ignore', invalid='ignore'): assert_(eq(np.divide(x, y), divide(xm, ym)))
def validationExterne(): """ Permet d'effectuer une validation externe entre l'image résultante de la réduction d'échelle et une image de température de surface calculée à partir des bandes 10 et 11 de Landsat 8 (disponibles sur EarthData). Les résultats de la validation externe sont des métriques de qualité en comparant les résultats de la réduction d'échelle à la température de surface calculée à 100m. Ces résultats sont présentés dans la console par des 'print' (lignes 129 à 144). """ # Match prediction result extent landsat_b10 = Image( r'data/LC08_L1TP_014028_20200706_20200721_01_T1_B10.TIF') landsat_b10.reprojectMatch( r'data/MOD11_L2.clipped_test2.tif'.split(".")[0] + '_subdivided_100m.tif', False) landsat_b10.setNewFile( landsat_b10.filename.replace(".TIF", "_reproject.tif")) # Get TOA radiance b10_array = landsat_b10.getArray(masked=True, lower_valid_range=1, upper_valid_range=65535) b10_array_radiance = ma.add(ma.multiply(b10_array, 0.00033420), 0.10000) # Get Brightness Temperature b10_array_brightness_temp = (1321.0789 / (ma.log( (774.8853 / b10_array_radiance) + 1))) - 273.15 # Get NDVI landsat_b4 = Image( r'data/LC08_L1TP_014028_20200706_20200721_01_T1_B4_reproject.tif') b4_DN = landsat_b4.getArray(masked=True, lower_valid_range=1, upper_valid_range=65535) b4 = np.add(np.multiply(b4_DN, float(0.00002)), float(-0.10)) landsat_b5 = Image( r'data/LC08_L1TP_014028_20200706_20200721_01_T1_B5_reproject.tif') b5_DN = landsat_b5.getArray(masked=True, lower_valid_range=1, upper_valid_range=65535) b5 = np.add(np.multiply(b5_DN, float(0.00002)), float(-0.10)) ndvi = np.divide(np.subtract(b5, b4), np.add(b5, b4), where=((np.add(b5, b4)) != 0)) # Get proportion of vegetation min_ndvi = ma.amin(ndvi) max_ndvi = ma.amax(ndvi) pv = ma.power( ma.divide(ma.subtract(ndvi, min_ndvi), (ma.subtract(max_ndvi, min_ndvi)), where=(ma.subtract(max_ndvi, min_ndvi)) != 0), 2) # Get emissivity emissivity = 0.004 * pv + 0.986 # Get Landsat 8 LST landsat_lst = b10_array_brightness_temp / ( 1 + (0.00115 * b10_array_brightness_temp / 1.4388) * ma.log(emissivity)) # Save LST image for visualization landsat_b10.save_band(landsat_lst, r'data/landsat_lst.tif') # Validation between both arrays predicted_lst = ma.masked_invalid( Image(r'data/MODIS_predit_100m.tif').getArray()) predicted_lst_with_residuals = ma.masked_invalid( Image(r'data/MODIS_predit_100m_avec_residus.tif').getArray()) predicted_lst = ma.filled(predicted_lst, 0) predicted_lst_with_residuals = ma.filled(predicted_lst_with_residuals, 0) # Without residuals print('Without residual correction') print('Mean Absolute Error (MAE):', metrics.mean_absolute_error(predicted_lst, landsat_lst)) print('Mean Squared Error:', metrics.mean_squared_error(predicted_lst, landsat_lst)) print('Root Mean Squared Error:', np.sqrt(metrics.mean_squared_error(predicted_lst, landsat_lst)), "°C") print( 'Accuracy:', 100 - np.mean(100 * ((abs(predicted_lst - landsat_lst)) / landsat_lst)), "%") print('Explained variance score (EVS):', metrics.explained_variance_score(predicted_lst, landsat_lst)) # With residuals print("\n") print('With residual correction') print( 'Mean Absolute Error (MAE):', metrics.mean_absolute_error(predicted_lst_with_residuals, landsat_lst)) print( 'Mean Squared Error:', metrics.mean_squared_error(predicted_lst_with_residuals, landsat_lst)) print( 'Root Mean Squared Error:', np.sqrt( metrics.mean_squared_error(predicted_lst_with_residuals, landsat_lst)), "°C") print( 'Accuracy:', 100 - np.mean(100 * ( (abs(predicted_lst_with_residuals - landsat_lst)) / landsat_lst)), "%") print( 'Explained variance score (EVS):', metrics.explained_variance_score(predicted_lst_with_residuals, landsat_lst))
def applyDownscaling(self, predictors, outputFile, residualCorrection=False, outputFile_withResidualCorrection=None, targetResolution=None): """ Entraîne un modèle de Random Forest Regression avec certains prédicteurs spécifiés dans une liste en entrée et applique par la suite la réduction d'échelle avec le modèle entraîné. Le résultat est sauvegardé dans une nouvelle image. Args: predictors (list): Liste de string des prédicteurs à inclure dans l'entraînement ou la prédiction de la réduction d'échelle. Cet argument doit prendre la forme suivante: ['NDVI', 'NDWI', 'NDBI', 'MNT', 'Pente'] avec des prédicteurs disponibles dans cette méthode. outputFile (string): Path vers le fichier dans lequel on souhaite sauvegarder le résultat de la réduction d'échelle à 100m. """ dataframe = self.secteur.getDf( predictors, train=True) # on va cherche le Pandas DataFrame du secteur dataframe = dataframe.replace(-9999.0, np.nan) dataframe = dataframe.dropna() predicteurs = dataframe.drop( 'LST', axis=1 ) # on retire la température de surface (LST) du DataFrame pour ne # conserver que les prédicteurs #predicteurs = predicteurs.dropna() # pour l'entraînement, on retire les valeurs Nulles modis_LST = dataframe['LST'] #modis_LST = modis_LST.dropna() # pour l'entraînement, on retire les valeurs Nulles modis_LST = modis_LST.ravel( ) # format accepté par le Random Forest Regression pour la variable dépendante Y # (une seule ligne) # Split de l'échantillon d'entraînement et de l'échantillon de test (échantillon de test = 25% de l'échantillon # total) test_sample_size = 0.25 X_train, X_test, y_train, y_test = train_test_split( predicteurs, modis_LST, test_size=test_sample_size, random_state=42) # Initialisation du régresseur avec 100 estimateurs regressor = RandomForestRegressor(n_estimators=100, random_state=42) # Entraînement du modèle regressor.fit(X_train, y_train) # ----------- Validation interne --------------- # Prédiction avec l'échantillon de test y_pred = regressor.predict(X_test) # Métriques de qualité sur le résultat prédit par rapport à l'échantillon de test (vérité) print("\n") print("Validation interne avec {}% des échantillons".format( test_sample_size * 100)) print('Coefficient of determination (R2):', metrics.r2_score(y_test, y_pred)) print('Mean Absolute Error (MAE):', metrics.mean_absolute_error(y_test, y_pred)) print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred)) print('Root Mean Squared Error:', np.sqrt(metrics.mean_squared_error(y_test, y_pred))) print('Accuracy:', 100 - np.mean(100 * ((abs(y_pred - y_test)) / y_test))) print('Explained variance score (EVS):', metrics.explained_variance_score(y_test, y_pred)) print("") # Importance de chacun des prédicteurs dans la prédiction print("Prédicteurs utilisés:", list(predicteurs.columns)) print("Importance de chaque prédicteur:", regressor.feature_importances_) print("") # Graphique de l'importance des prédicteurs fig, ax = plt.subplots() y_pos = np.arange(len(list(predicteurs.columns))) ax.barh(y_pos, regressor.feature_importances_, align='center') ax.set_yticks(y_pos) ax.set_yticklabels(list(predicteurs.columns)) plt.show() # Affichage des résidus par rapport à l'échantillon de test (vérité) test_residuals = y_test - y_pred sns.scatterplot(x=y_test, y=test_residuals) plt.axhline(y=0, color='r', ls='--') plt.show() # ------------- Prédiction ------------------ # préparer les données pour la prédiction (downscaling) à 100m self.secteur.prepareData(train_model=False, targetResolution=targetResolution) # Prédiction dataframe_predict = self.secteur.getDf(predictors, train=False) #dataframe_predict = dataframe_predict.fillna(0) # à inclure si on veut masquer les nuages à 100m aussi y_downscale = regressor.predict(dataframe_predict.drop('LST', axis=1)) # *********** (à faire avec Landsat LST) **************** # Métriques de qualité sur le résultat prédit par rapport à l'échantillon de vérité terrain # print('Mean Absolute Error (MAE):', metrics.mean_absolute_error(y_test, y_pred)) # print('Mean Squared Error:', metrics.mean_squared_error(y_test, y_pred)) # print('Root Mean Squared Error:', np.sqrt(metrics.mean_squared_error(y_test, y_pred))) # Importance de chacun des prédicteurs (NDVI, NDWI, NDBI) dans la prédiction #print("Importance de chaque prédicteur", regressor.feature_importances_) # Affichage des résidus par rapport à l'échantillon de vérité terrain # ************* (à faire avec Landsat LST) ************** # test_residuals = y_test - y_pred # sns.scatterplot(x=y_test, y=test_residuals) # plt.axhline(y=0, color='r', ls='--') # plt.show() # sauvegarder le résultat avec une autre image (de mêmes dimensions et avec la même référence spatiale) # comme référence reference_image = Image(self.secteur.modis_image.lst ) # LST MODIS subdivisée (à 100m ou 30m) y_downscale_masked = ma.masked_array(y_downscale, self.secteur.mask.ravel()) y_downscale_masked = ma.filled( y_downscale_masked, np.nan) # on retire les valeurs masquées du output y_downscale_masked = y_downscale_masked.reshape( reference_image.ysize, reference_image.xsize) reference_image.save_band(y_downscale_masked, outputFile) # ------------- Correction pour les résidus ------------------ if residualCorrection: predicted_image = Image(outputFile) # ramener à 1km predicted_image.reprojectMatch( self.secteur.modis_image.lst.replace("_reproject", ""), reduce_zone=True) resampled_predicted_image = Image( outputFile.replace(".tif", "_reproject.tif")) # Conversion du array MODIS LST en un format compatible au Random Forest Regression tmp_lst_image_1km = Image(self.secteur.modis_image.lst) tmp_lst_image_1km.reprojectMatch( self.secteur.modis_image.lst.replace("_reproject", ""), reduce_zone=True) lst_image_1km = Image( self.secteur.modis_image.lst.replace("_reproject", "_reproject_reproject")) modis_array = lst_image_1km.getArray(masked=True, lower_valid_range=7500, upper_valid_range=65535) # convertir à des températures de surface en Celsius lst_metadata = lst_image_1km.getMetadata() # vérifier si le scale_factor est présent dans les métadonnées (c'est le cas pour AppEEARS, pas EarthData) if 'scale_factor' in lst_metadata: scale_factor = float( lst_metadata['scale_factor']) # multiplier par 0.02 add_offset = float(lst_metadata['add_offset']) else: scale_factor = float(0.02) add_offset = float(0) # conversion en Kelvin, puis en Celsius kelvin_array = np.add(np.multiply(modis_array, scale_factor), add_offset) lst_celsius_array = np.subtract(kelvin_array, 273.15) lst_image_1km.save_band(lst_celsius_array, r'data/MODIS_1km_Celsius.tif') # Calcul des résidus à 1km residus_1km = ma.subtract(lst_celsius_array, resampled_predicted_image.getArray()) # Sauvegarder l'image 1km pour pouvoir la ramener à 100m par la suite residus_1km_masked = ma.filled( residus_1km, np.nan) # on retire les valeurs masquées du output lst_image_1km.save_band(residus_1km_masked, r'data/residus_1km.tif') residus_1km_load = Image(r'data/residus_1km.tif') # Résidus de 1km -> 100m if targetResolution == 100: residus_1km_load.reproject(r'data/residus_1km.tif', r'data/residus_100m.tif', 'EPSG:32618', 'np.nan', '100.0', 'cubic') # Application des résidus sur le résultat residus_100m = Image(r'data/residus_100m.tif') predicted_image_with_residuals = ma.add( predicted_image.getArray(), residus_100m.getArray()) # Sauvegarder le résultat residus_100m.save_band(predicted_image_with_residuals, outputFile_withResidualCorrection) elif targetResolution == 30: residus_1km_load.reproject(r'data/residus_1km.tif', r'data/residus_30m.tif', 'EPSG:32618', 'np.nan', '30.0', 'cubic') # Application des résidus sur le résultat residus_30m = Image(r'data/residus_30m.tif') predicted_image_with_residuals = ma.add( predicted_image.getArray(), residus_30m.getArray()) # Sauvegarder le résultat residus_30m.save_band(predicted_image_with_residuals, outputFile_withResidualCorrection)
def flipLongitudesToPositive(lons): lons[lons < 0] = ma.add(lons[lons < 0],\ 360*ma.masked_array(np.ones(lons.shape), lons >= 0)[lons < 0]) return lons
def flipLongitudesToSymmetric(lons): lons[lons >= 180] = ma.add(lons[lons >= 180],\ -360*ma.masked_array(np.ones(lons.shape), lons < 180)[lons >= 180]) return lons
windspeeds = np.ma.empty(shape=(nlat, nlon)) curl = np.ma.empty_like(windspeeds) u10mask = ma.getmaskarray(u10[:]) u10_masked_indices = ma.where(u10mask == True) u10_unmasked_indices = ma.where(u10mask == False) two_array_wind = ma.array( np.full(shape=(nlat, nlon), fill_value=2.0, dtype=float)) two_array_wind[u10_masked_indices] = ma.masked print('Calculating windspeeds...') windspeeds = ma.sqrt( ma.add(ma.power(u10, two_array_wind), ma.power(v10, two_array_wind))) fig = plt.figure() ax1 = fig.add_subplot(1, 2, 1, projection=ccrs.PlateCarree()) ax1.coastlines() ax1.contourf(lon[:], lat[:], windspeeds[:], cmap='cool') ax1.quiver(lon[::2], lat[::2], u10[::2, ::2], v10[::2, ::2], scale=250) CONV_CRIT = 0.00005 #convergence critereon (fractional change) [] CONVECT = 0.0 #convective parameter warn = 1 #warning are given eqv_neut = 0 #output winds are winds rather than equivalent neutral winds z_wanted = 10.0 #height to which winds, potential temp, and humidity are adjusted flux_model = 9 #BVW model=0 Qnet = 5.0