-
Notifications
You must be signed in to change notification settings - Fork 153
Add recipe for sea ice area and extents in southern polar region #3607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
flicj191
wants to merge
31
commits into
main
Choose a base branch
from
recipe_seaice_areaextents_sh
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
e1866a3
add seaice recipe files
flicj191 faf1f04
code cleaning
flicj191 9bb7e61
code cleaning
flicj191 17de6e0
code formatting
flicj191 e262c9f
Merge branch 'main' into recipe_seaice_areaextents_sh
flicj191 bae1377
edit references
flicj191 a7f09bd
codacy issues
flicj191 36d149b
codacy clean up
flicj191 a60d218
flake clean up
flicj191 e03c8f5
flake clean up
flicj191 e8ad989
add docs, authors and save data
flicj191 81a39fe
Merge branch 'main' into recipe_seaice_areaextents_sh
flicj191 475bb80
formatting
flicj191 21be9a8
remove blank line
flicj191 87a6116
codacy docstring
flicj191 78d7e84
docstring edit
flicj191 1bfcf8f
Merge branch 'main' into recipe_seaice_areaextents_sh
flicj191 9495f3f
minor code edits
flicj191 0bfbd99
Apply suggestions from review
flicj191 704e769
Update esmvaltool/config-references.yml
flicj191 547ae63
Apply enumerate
flicj191 a63fa68
edits
flicj191 1760bec
preprocessers for trends
flicj191 92ec330
change trends script for preprocessed data
flicj191 b51c995
clean up script, add preprocessor for map
flicj191 cb64a33
edit map preprocessors
flicj191 a5204f5
change to method to create extents figure
flicj191 e1f697f
clean up
flicj191 abf49c4
codacy clean
flicj191 f6c682f
format
flicj191 60034f6
Merge branch 'main' into recipe_seaice_areaextents_sh
flicj191 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+81.5 KB
doc/sphinx/source/recipes/figures/seaice_extents_sh/map_difference.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| .. _recipes_seaice_extents_sh: | ||
|
|
||
| Sea Ice area and extents | ||
| ======================== | ||
|
|
||
| Overview | ||
| -------- | ||
|
|
||
| This recipe plots sea ice concentration from CICE (sea ice model) output | ||
| around the southern polar region and compares it to the NSIDC CDR | ||
| (National Snow and Ice Data Centre, Climate Data Record) dataset. | ||
|
|
||
|
|
||
| Available recipes and diagnostics | ||
| --------------------------------- | ||
|
|
||
| Recipes are stored in esmvaltool/recipes/ | ||
|
|
||
| * recipe_seaice_extents_sh.yml | ||
|
|
||
| Diagnostics are stored in esmvaltool/diag_scripts/seaice_area_extents/ | ||
|
|
||
| * seaicearea_trends.py: plot minima and maxima sea ice area trends | ||
| * seaice_mapextents.py: plot sea ice extent and differences to Observations | ||
|
|
||
|
|
||
| User settings in recipe | ||
| ----------------------- | ||
|
|
||
| #. Script seaice_mapextents.py | ||
|
|
||
| *Required settings for script* | ||
|
|
||
| * `months`: months by month number which the mean are to be plotted | ||
|
|
||
|
|
||
| Variables | ||
| --------- | ||
|
|
||
| * siconc (seaIce, monthly, longitude latitude time) | ||
| * areacello (fx) | ||
|
|
||
|
|
||
| Observations and reformat scripts | ||
| --------------------------------- | ||
|
|
||
| *Note: (1) obs4MIPs data can be used directly without any preprocessing; | ||
| (2) see headers of reformat scripts for non-obs4MIPs data for download | ||
| instructions.* | ||
|
|
||
| * NSIDC CDR sh (siconc - esmvaltool/cmorizers/data/formatters/datasets/nsidc_g02202_sh.py) | ||
|
|
||
|
|
||
| References | ||
| ---------- | ||
|
|
||
| https://cosima-recipes.readthedocs.io/en/latest/Examples/Sea_Ice_Area_Concentration_Volume_with_Obs.html | ||
|
|
||
| Example plots | ||
| ------------- | ||
|
|
||
| .. _trends: | ||
| .. figure:: /recipes/figures/seaice_extents_sh/min_trend.png | ||
| :align: center | ||
|
|
||
| Minima trends of sea ice area with observation data. ACCESS OM model data years from 0, added 1652 years to model years for comparability. | ||
|
|
||
| .. _map extents: | ||
| .. figure:: /recipes/figures/seaice_extents_sh/map_difference.png | ||
| :align: center | ||
|
|
||
| Difference and extents of models with observations for selected months. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
125 changes: 125 additions & 0 deletions
125
esmvaltool/diag_scripts/seaice_area_extents/seaice_mapextents.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| """Diagnostic script to plot extent and differences. | ||
|
|
||
| based on code from Anton Steketee's COSIMA recipes notebook | ||
| https://cosima-recipes.readthedocs.io/en/latest/Examples/Sea_Ice_Area_Concentration_Volume_with_Obs.html | ||
| """ | ||
|
|
||
| import calendar | ||
| import logging | ||
| import os | ||
|
|
||
| import iris | ||
| import iris.plot as iplt | ||
| import matplotlib.lines as mlines | ||
| import matplotlib.pyplot as plt | ||
| import numpy as np | ||
| from cartopy.crs import SouthPolarStereo | ||
| from esmvalcore.preprocessor import extract_month | ||
|
|
||
| from esmvaltool.diag_scripts.shared import ( | ||
| group_metadata, | ||
| select_metadata, | ||
| run_diagnostic, | ||
| save_figure, | ||
| ) | ||
|
|
||
| # This part sends debug statements to stdout | ||
| logger = logging.getLogger(os.path.basename(__file__)) | ||
|
|
||
|
|
||
| def map_fig_diff(model_dict, obs_si, months): | ||
| """Create map with model dictionary: labels, cubes.""" | ||
| # figure set up, width 9 for 2 models | ||
| figure = plt.figure(figsize=(9, len(months) * 3.5)) | ||
| j = 0 # to iterate through positions on figure | ||
|
|
||
| for mon in months: # eg.[2,9] | ||
| i = 1 | ||
| obs_cube = extract_month(obs_si, mon) | ||
| for mod_label, mod_si in model_dict.items(): | ||
| mod_cube = extract_month(mod_si, mon) | ||
|
|
||
| out = mod_cube.copy() | ||
| diff = mod_cube.data - obs_cube.data | ||
| out.data = diff | ||
|
|
||
| plt.subplot(len(months), 3, i + j * 3, | ||
| projection=SouthPolarStereo(true_scale_latitude=-70)) | ||
|
|
||
| diffmap = iplt.contourf(out, levels=np.arange(-90, 91, 20), | ||
| cmap='RdBu') | ||
|
|
||
| iplt.contour(obs_cube, levels=[15], colors=['yellow']) | ||
| iplt.contour(mod_cube, levels=[15], | ||
| linewidths=1.0, colors=['black']) | ||
|
|
||
| plt.title(calendar.month_abbr[mon] + ' ' + mod_label) | ||
|
|
||
| i += 1 | ||
| j += 1 | ||
|
|
||
| line_cdr = mlines.Line2D([], [], color='yellow', label="Observed Extent") | ||
| line_mod = mlines.Line2D([], [], color='black', label="Modelled Extent") | ||
|
|
||
| plt.legend(handles=[line_cdr, line_mod], loc='center left', | ||
| bbox_to_anchor=(1.2, 0.5)) | ||
| cax = plt.axes([0.7, 0.55, 0.04, 0.3]) | ||
| _ = plt.colorbar(diffmap, cax=cax, | ||
| label='Difference in \nSea Ice Concentration') | ||
|
|
||
| plt.subplots_adjust(left=0.05, bottom=0.05, | ||
| right=0.95, top=0.95, | ||
| wspace=0.05, hspace=0.05) | ||
|
|
||
| return figure | ||
|
flicj191 marked this conversation as resolved.
|
||
|
|
||
|
|
||
| def main(cfg): | ||
| """Compute.""" | ||
| # Get the preprocessed data that we will use as input. | ||
| input_data = cfg['input_data'].values() | ||
|
|
||
| groups = group_metadata(input_data, 'variable_group') | ||
| # assign obs_si - select | ||
| selection = select_metadata(input_data, project='OBS6') | ||
| obs_si = iris.load_cube(selection[0]['filename']) | ||
|
|
||
| for group_name in groups.keys(): | ||
| mod_dict = {} | ||
| ancestor_filels = [] | ||
| logger.info("Processing variable %s", group_name) | ||
|
|
||
| for attr in groups[group_name]: | ||
| if attr['project'].startswith('OBS'): | ||
| logger.info("Load OBS dataset %s", attr['dataset']) | ||
| obs_si = iris.load_cube(attr['filename']) | ||
| else: | ||
| logger.info("load model dataset %s", attr['dataset']) | ||
| mod_dict[attr['dataset']] = iris.load_cube(attr['filename']) | ||
| ancestor_filels.append(attr['filename']) | ||
|
|
||
| logger.info("creating map differences") | ||
| mapfig = map_fig_diff(mod_dict, obs_si, cfg['months']) | ||
|
|
||
| provenance_record = get_provenance_record(ancestor_filels) | ||
| save_figure(group_name, provenance_record, cfg, figure=mapfig) | ||
|
|
||
|
|
||
| def get_provenance_record(ancestor_files): | ||
| """Build provenance dictionary.""" | ||
| record = { | ||
| 'ancestors': ancestor_files, | ||
| 'authors': ['chun_felicity', 'steketee_anton'], | ||
| 'caption': 'siconc observations difference from model', | ||
| 'domains': ['shpolar'], | ||
| 'plot_types': ['polar'], | ||
| 'references': [], | ||
| 'statistics': ['diff'], | ||
| } | ||
| return record | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
|
|
||
| with run_diagnostic() as config: | ||
| main(config) | ||
78 changes: 78 additions & 0 deletions
78
esmvaltool/diag_scripts/seaice_area_extents/seaicearea_trends.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| """Diagnostic script to plot minima and maxima trends. | ||
|
|
||
| based on code from Anton Steketee's COSIMA cookbook notebook | ||
| https://cosima-recipes.readthedocs.io/en/latest/Examples/Sea_Ice_Area_Concentration_Volume_with_Obs.html | ||
| """ | ||
|
|
||
| import logging | ||
| import os | ||
|
|
||
| import iris | ||
| import matplotlib.pyplot as plt | ||
| from iris import quickplot | ||
|
|
||
| from esmvaltool.diag_scripts.shared import run_diagnostic, save_figure | ||
|
|
||
| # This part sends debug statements to stdout | ||
| logger = logging.getLogger(os.path.basename(__file__)) | ||
|
|
||
|
|
||
| def _prom_dim_coord(cube, _field, _filename): | ||
| iris.util.promote_aux_coord_to_dim_coord(cube, 'year') | ||
|
|
||
|
|
||
| def plot_trends(datagroup, provenance_record, cfg): | ||
| """Create plot for min and max groups.""" | ||
| for variable_group, attributes in datagroup.items(): | ||
| plt.clf() | ||
| for (filep, vname, datalabel, offset) in attributes: | ||
| cube = iris.load_cube(filep, vname, _prom_dim_coord) | ||
| if offset: | ||
| cube.coord('year').points = [y + offset for y in | ||
| cube.coord('year').points] | ||
| quickplot.plot(cube, label=datalabel) | ||
|
|
||
| plt.title(f"Trends in Sea-Ice {variable_group.split('_')[1]}ima") | ||
| plt.legend(loc='upper left') | ||
| plt.ylabel('Sea-Ice Area (km2)') | ||
|
|
||
| save_figure(variable_group, provenance_record, cfg, dpi=300) | ||
|
|
||
|
|
||
| def main(cfg): | ||
| """Compute sea ice area for each input dataset.""" | ||
| provenance_record = { | ||
| 'caption': "sea ice trends southern hemisphere", | ||
| 'authors': [ | ||
| 'chun_felicity', | ||
| 'steketee_anton' | ||
| ], | ||
| 'references': [''], | ||
| 'ancestors': list(cfg['input_data'].keys()), | ||
| } | ||
| input_data = cfg['input_data'].values() | ||
|
|
||
| datagroup = {} # for each variable min and max | ||
|
|
||
| for dataset in input_data: | ||
| # Load the data | ||
| if 'offset_years' in dataset: | ||
| input_file = (dataset['filename'], dataset['short_name'], | ||
| dataset['dataset'], dataset['offset_years']) | ||
| else: | ||
| input_file = (dataset['filename'], dataset['short_name'], | ||
| dataset['dataset'], None) | ||
| # key for different models | ||
| logger.info("Dataset: %s", {dataset['long_name']}) | ||
| if dataset['variable_group'] not in datagroup: | ||
| datagroup[dataset['variable_group']] = [] | ||
| datagroup[dataset['variable_group']].append(input_file) | ||
|
|
||
| logger.info(datagroup) | ||
| plot_trends(datagroup, provenance_record, cfg) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
|
|
||
| with run_diagnostic() as config: | ||
| main(config) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.