def plot_cdf(cfg, psi_cube, ecs_cube, obs_cube): """Plot cumulative distribution function of ECS.""" confidence_level = cfg.get('confidence_level', 0.66) (ecs_lin, ecs_pdf) = ec.gaussian_pdf(psi_cube.data, ecs_cube.data, np.mean(obs_cube.data), np.std(obs_cube.data)) ecs_cdf = ec.cdf(ecs_lin, ecs_pdf) # Provenance filename = 'cdf_{}'.format(obs_cube.attributes['dataset']) netcdf_path = get_diagnostic_filename(filename, cfg) cube = iris.cube.Cube(ecs_cdf, var_name='cdf', long_name='Cumulative distribution function', units='1') cube.add_aux_coord( iris.coords.AuxCoord(ecs_lin, **ih.convert_to_iris(ECS_ATTRS)), 0) io.iris_save(cube, netcdf_path) project = _get_project(cfg) provenance_record = get_provenance_record( "The CDF for ECS. The horizontal dot-dashed lines show the {}% " "confidence limits. The orange histograms show the prior " "distributions that arise from equal weighting of the {} models in " "0.5 K bins.".format(int(confidence_level * 100), project), ['mean'], ['other'], _get_ancestor_files(cfg, obs_cube.attributes['dataset'])) # Plot if cfg['write_plots']: AXES.plot(ecs_lin, ecs_cdf, color='black', linewidth=2.0, label='Emergent constraint') AXES.hist(ecs_cube.data, bins=6, range=(2.0, 5.0), cumulative=True, density=True, color='orange', label='{} models'.format(project)) AXES.axhline((1.0 - confidence_level) / 2.0, color='black', linestyle='dashdot') AXES.axhline((1.0 + confidence_level) / 2.0, color='black', linestyle='dashdot') # Plot appearance AXES.set_title('CDF of emergent constraint') AXES.set_xlabel('ECS / K') AXES.set_ylabel('CDF') legend = AXES.legend(loc='upper left') # Save plot provenance_record['plot_file'] = _save_fig(cfg, filename, legend) # Write provenance with ProvenanceLogger(cfg) as provenance_logger: provenance_logger.log(netcdf_path, provenance_record)
def plot_pdf(cfg, psi_cube, ecs_cube, obs_cube): """Plot probability density function of ECS.""" obs_mean = np.mean(obs_cube.data) obs_std = np.std(obs_cube.data) (ecs_lin, ecs_pdf) = ec.gaussian_pdf(psi_cube.data, ecs_cube.data, obs_mean, obs_std) # Provenance filename = 'pdf_{}'.format(obs_cube.attributes['dataset']) netcdf_path = get_diagnostic_filename(filename, cfg) cube = iris.cube.Cube(ecs_pdf, var_name='pdf', long_name='Probability density function', units='K-1') cube.add_aux_coord( iris.coords.AuxCoord(ecs_lin, **ih.convert_to_iris(ECS_ATTRS)), 0) io.iris_save(cube, netcdf_path) project = _get_project(cfg) provenance_record = get_provenance_record( "The PDF for ECS. The orange histograms show the prior distributions " "that arise from equal weighting of the {} models in 0.5 K bins.". format(project), ['mean'], ['other'], _get_ancestor_files(cfg, obs_cube.attributes['dataset'])) # Plot if cfg['write_plots']: AXES.plot(ecs_lin, ecs_pdf, color='black', linewidth=2.0, label='Emergent constraint') AXES.hist(ecs_cube.data, bins=6, range=(2.0, 5.0), density=True, color='orange', label='{} models'.format(project)) # Plot appearance AXES.set_title('PDF of emergent constraint') AXES.set_xlabel('ECS / K') AXES.set_ylabel('Probability density') legend = AXES.legend(loc='upper left') # Save plot provenance_record['plot_file'] = _save_fig(cfg, filename, legend) # Write provenance with ProvenanceLogger(cfg) as provenance_logger: provenance_logger.log(netcdf_path, provenance_record)
def get_constraint(x_data, y_data, x_ref, x_ref_err): """Print constraint value for Y axis.""" (feature, feature_units, label, label_units) = _get_tags(x_data, y_data) x_data = x_data.values.squeeze() y_data = y_data.values.squeeze() x_ref = x_ref.values.squeeze() x_ref_err = x_ref_err.values.squeeze() (y_data_lin, y_pdf) = ec.gaussian_pdf(x_data, y_data, x_ref, x_ref_err**2) y_mean = np.sum(y_data_lin * y_pdf) / np.sum(y_pdf) y_var = np.sum((y_data_lin - y_mean)**2 * y_pdf) / np.sum(y_pdf) y_std = np.sqrt(y_var) lines = ec.regression_surface(x_data, y_data) logger.info("Observational constraint on '%s': (%.3f ± %.3f) %s", feature, x_ref, x_ref_err, feature_units) logger.info("Constraint on target variable '%s': (%.3f ± %.3f) %s", label, y_mean, y_std, label_units) logger.info("R2 of emergent relationship: %.3f (p = %.4f)", lines['R2'], lines['p'][0]) return (y_mean, y_std)
def get_ecs_range(cfg, psi_cube, ecs_cube, obs_cube): """Get constrained ecs range.""" confidence_level = cfg.get('confidence_level', 0.66) conf_low = (1.0 - confidence_level) / 2.0 conf_high = (1.0 + confidence_level) / 2.0 # Calculate PDF and CDF (ecs_lin, ecs_pdf) = ec.gaussian_pdf(psi_cube.data, ecs_cube.data, np.mean(obs_cube.data), np.std(obs_cube.data)) ecs_cdf = ec.cdf(ecs_lin, ecs_pdf) # Calculate constrained ECS range ecs_mean = ecs_lin[np.argmax(ecs_pdf)] ecs_index_range = np.where((ecs_cdf >= conf_low) & (ecs_cdf <= conf_high))[0] ecs_range = ecs_lin[ecs_index_range] ecs_low = min(ecs_range) ecs_high = max(ecs_range) return (ecs_mean, ecs_low, ecs_high)
def main(cfg): """Run the diagnostic.""" input_data = ( select_metadata(cfg['input_data'].values(), short_name='tas') + select_metadata(cfg['input_data'].values(), short_name='tasa')) if not input_data: raise ValueError("This diagnostics needs 'tas' or 'tasa' variable") # Get time-dependent data (tas_cubes, tas_obs) = get_tas(input_data) (psi_cubes, psi_obs) = get_psi(cfg) # Get scalar psi, ECS and climate feedback parameter for models (psi_cube, ecs_cube, lambda_cube) = get_external_cubes(cfg) # Plots for obs_name in tas_obs: logger.info("Observation for tas: %s", obs_name) plot_temperature_anomaly(cfg, tas_cubes, lambda_cube, obs_name) for obs_name in psi_obs: logger.info("Observation for psi: %s", obs_name) plot_psi(cfg, psi_cubes, lambda_cube, obs_name) obs_cube = psi_cubes[obs_name] plot_emergent_relationship(cfg, psi_cube, ecs_cube, lambda_cube, obs_cube) (ecs_lin, ecs_pdf) = ec.gaussian_pdf(psi_cube.data, ecs_cube.data, np.mean(obs_cube.data), np.var(obs_cube.data)) plot_pdf(cfg, ecs_lin, ecs_pdf, ecs_cube, obs_name) plot_cdf(cfg, ecs_lin, ecs_pdf, ecs_cube, obs_name) # Print ECS range ecs_range = get_ecs_range(cfg, ecs_lin, ecs_pdf) logger.info("Observational constraint: Ψ = (%.2f ± %.2f) K", np.mean(obs_cube.data), np.std(obs_cube.data)) logger.info( "Constrained ECS range: (%.2f - %.2f) K with best " "estimate %.2f K", ecs_range[1], ecs_range[2], ecs_range[0])