def generate_reference_data_for_pcquick_filter_tests(): orig_long = np.arange(0., 359.9, 2.5) test_olr = olr.load_noaa_interpolated_olr(olr_data_filename) lat = np.array([0]) test_olr_part = olr.interpolate_spatial_grid(test_olr, lat, orig_long) olrdata_filtered = qfilter.filter_olr_for_mjo_pc_calculation_1d_spectral_smoothing( test_olr_part) filename = Path( str(reference_file_filterOLRForMJO_PCQuick_Calculation_lat0) + ".newcalc") olrdata_filtered.save_to_npzfile(filename) lat = np.array([5]) test_olr_part = olr.interpolate_spatial_grid(test_olr, lat, orig_long) olrdata_filtered = qfilter.filter_olr_for_mjo_pc_calculation_1d_spectral_smoothing( test_olr_part) filename = Path( str(reference_file_filterOLRForMJO_PCQuick_Calculation_lat5) + ".newcalc") olrdata_filtered.save_to_npzfile(filename) lat = np.array([-10]) test_olr_part = olr.interpolate_spatial_grid(test_olr, lat, orig_long) olrdata_filtered = qfilter.filter_olr_for_mjo_pc_calculation_1d_spectral_smoothing( test_olr_part) filename = Path( str(reference_file_filterOLRForMJO_PCQuick_Calculation_latmin10) + ".newcalc") olrdata_filtered.save_to_npzfile(filename)
def test_mjoindices_reference_validation_filterOLRForMJO_PC_Calculation(): errors = [] orig_long = np.arange(0., 359.9, 2.5) test_olr = olr.load_noaa_interpolated_olr(olr_data_filename) lat = np.array([0]) test_olr_part = olr.interpolate_spatial_grid(test_olr, lat, orig_long) target = wkfilter.filter_olr_for_mjo_pc_calculation(test_olr_part) control = olr.restore_from_npzfile(reference_file_filterOLRForMJO_PC_Calculation_lat0) if not target.close(control): errors.append("Filtered OLR for latitude 0 not identical") lat = np.array([5]) test_olr_part = olr.interpolate_spatial_grid(test_olr, lat, orig_long) target = wkfilter.filter_olr_for_mjo_pc_calculation(test_olr_part) control = olr.restore_from_npzfile(reference_file_filterOLRForMJO_PC_Calculation_lat5) if not target.close(control): errors.append("Filtered OLR for latitude 5 not identical") lat = np.array([-10]) test_olr_part = olr.interpolate_spatial_grid(test_olr, lat, orig_long) target = wkfilter.filter_olr_for_mjo_pc_calculation(test_olr_part) control = olr.restore_from_npzfile(reference_file_filterOLRForMJO_PC_Calculation_latmin10) if not target.close(control): errors.append("Filtered OLR for latitude -10 not identical") assert not errors, "errors occurred:\n{}".format("\n".join(errors))
def test_completeOMIReproduction_coarsegrid(tmp_path): errors = [] # Calculate EOFs raw_olr = olr.load_noaa_interpolated_olr(olr_data_filename) shorter_olr = olr.restrict_time_coverage(raw_olr, np.datetime64('1979-01-01'), np.datetime64('2012-12-31')) coarse_lat = np.arange(-20., 20.1, 8.0) coarse_long = np.arange(0., 359.9, 20.0) interpolated_olr = olr.interpolate_spatial_grid(shorter_olr, coarse_lat, coarse_long) eofs = omi.calc_eofs_from_olr(interpolated_olr, sign_doy1reference=True, interpolate_eofs=True, strict_leap_year_treatment=True) eofs.save_all_eofs_to_npzfile( tmp_path / "test_completeOMIReproduction_coarsegrid_EOFs.npz") # Validate EOFs against mjoindices own reference (results should be equal) mjoindices_reference_eofs = eof.restore_all_eofs_from_npzfile( mjoindices_reference_eofs_filename_coarsegrid) for idx, target_eof in enumerate(eofs.eof_list): if not mjoindices_reference_eofs.eof_list[idx].close(target_eof): errors.append( "mjoindices-reference-validation: EOF data at index %i is incorrect" % idx) # Calculate PCs raw_olr = olr.load_noaa_interpolated_olr(olr_data_filename) pcs = omi.calculate_pcs_from_olr(raw_olr, eofs, np.datetime64("1979-01-01"), np.datetime64("2018-08-28"), use_quick_temporal_filter=False) pc_temp_file = tmp_path / "test_completeOMIReproduction_coarsegrid_PCs.txt" pcs.save_pcs_to_txt_file(pc_temp_file) # Validate PCs against mjoindices own reference (results should be equal) # Reload pcs instead of using the calculated ones, because the saving routine has truncated some decimals of the # reference values. So do the same with the testing target pcs. pcs = pc.load_pcs_from_txt_file(pc_temp_file) mjoindices_reference_pcs = pc.load_pcs_from_txt_file( mjoindices_reference_pcs_filename_coarsegrid) if not np.all(mjoindices_reference_pcs.time == pcs.time): errors.append( "mjoindices-reference-validation: Dates of PCs do not match.") if not np.allclose(mjoindices_reference_pcs.pc1, pcs.pc1): errors.append( "mjoindices-reference-validation: PC1 values do not match.") if not np.allclose(mjoindices_reference_pcs.pc2, pcs.pc2): errors.append( "mjoindices-reference-validation: PC2 values do not match.") assert not errors, "errors occurred:\n{}".format("\n".join(errors))
def calculate_pcs_from_olr(olrdata: olr.OLRData, eofdata: eof.EOFDataForAllDOYs, period_start: np.datetime64, period_end: np.datetime64, use_quick_temporal_filter=False) -> pc.PCData: """ This major function computes PCs according to the OMI algorithm based on given OLR data and previously calculated EOFs. :param olrdata: The OLR dataset. The spatial grid must fit to that of the EOFs :param eofdata: The previously calculated DOY-dependent EOFs. :param period_start: the beginning of the period, for which the PCs should be calculated. :param period_end: the ending of the period, for which the PCs should be calculated. :param use_quick_temporal_filter: There are two implementations of the temporal filtering: First, the original Wheeler-Kiladis-Filter, which is closer to the original implementation while being slower (because it is based on a 2-dim FFT) or a 1-dim FFT Filter. Setting this parameter to True uses the quicker 1-dim implementation. The results are quite similar. :return: The PC time series. """ resticted_olr_data = olr.restrict_time_coverage(olrdata, period_start, period_end) resampled_olr_data = olr.interpolate_spatial_grid(resticted_olr_data, eofdata.lat, eofdata.long) if use_quick_temporal_filter: filtered_olr_data = qfilter.filter_olr_for_mjo_pc_calculation_1d_spectral_smoothing( resampled_olr_data) else: filtered_olr_data = wkfilter.filter_olr_for_mjo_pc_calculation( resampled_olr_data) raw_pcs = regress_3dim_data_onto_eofs(filtered_olr_data, eofdata) normalization_factor = 1 / np.std(raw_pcs.pc1) pc1 = np.multiply(raw_pcs.pc1, normalization_factor) pc2 = np.multiply(raw_pcs.pc2, normalization_factor) return pc.PCData(raw_pcs.time, pc1, pc2)
'')) / "example_data" / "omi_recalc_example_plots_coarsegrid" # ############## Calculation of the EOFs ################### if not fig_dir.exists(): fig_dir.mkdir(parents=True, exist_ok=False) # Load the OLR data. # This is the first place to insert your own OLR data, if you want to compute OMI for a different dataset. raw_olr = olr.load_noaa_interpolated_olr(olr_data_filename) # Restrict dataset to the original length for the EOF calculation (Kiladis, 2014). shorter_olr = olr.restrict_time_coverage(raw_olr, np.datetime64('1979-01-01'), np.datetime64('2012-12-31')) # This is the line, where the spatial grid is changed. interpolated_olr = olr.interpolate_spatial_grid(shorter_olr, coarse_lat, coarse_long) # Diagnosis plot of the loaded OLR data. fig = olr.plot_olr_map_for_date(interpolated_olr, np.datetime64("2010-01-01")) fig.show() fig.savefig(fig_dir / "OLR_map.png") # Calculate the eofs. In the postprocessing, the signs of the EOFs are adjusted and the EOF in a period # around DOY 300 are replaced by an interpolation see Kiladis, 2014). # The switch strict_leap_year_treatment has major implications only for the EOFs calculated for DOY 366 and causes only # minor differences for the other DOYs. While the results for setting strict_leap_year_treatment=False are closer to the # original values, the calculation strict_leap_year_treatment=True is somewhat more stringently implemented using # built-in datetime functionality. # See documentation of mjoindices.tools.find_doy_ranges_in_dates() for details. eofs = omi.calc_eofs_from_olr(interpolated_olr, sign_doy1reference=True,