Skip to content
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

Update plotting routines in QC script #355

Merged
merged 5 commits into from
Aug 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 98 additions & 20 deletions configuration/scripts/tests/QC/cice.t-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,48 +358,102 @@ def skill_test(path_a, fname, data_a, data_b, num_files, hemisphere):
logger.info('Quadratic Skill Test Failed for %s Hemisphere', hemisphere)
return False

def plot_data(data, lat, lon, units):
'''This function plots CICE data and creates a .png file (ice_thickness_map.png).'''
def plot_data(data, lat, lon, units, case, plot_type):
'''This function plots CICE data and creates a .png file.'''

try:
logger.info('Creating map of the data (ice_thickness_map.png)')
# Load the necessary plotting libraries
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from mpl_toolkits.axes_grid1 import make_axes_locatable
except ImportError:
logger.warning('Error loading necessary Python modules in plot_data function')
return

# Suppress Matplotlib deprecation warnings
import warnings
warnings.filterwarnings("ignore", category=UserWarning)

# Create the figure and axis
fig = plt.figure(figsize=(12, 8))
ax = fig.add_axes([0.05, 0.08, 0.9, 0.9])
fig, axes = plt.subplots(nrows=1, ncols=2,figsize=(14, 8))

# Plot the northern hemisphere data as a scatter plot
# Create the basemap, and draw boundaries
m = Basemap(projection='kav7', lon_0=180., resolution='l')
m.drawmapboundary(fill_color='white')
plt.sca(axes[0])
m = Basemap(projection='npstere', boundinglat=35,lon_0=270, resolution='l')
m.drawcoastlines()
m.fillcontinents()
m.drawcountries()

# Plot the data as a scatter plot
x, y = m(lon, lat)
sc = m.scatter(x, y, c=data, cmap='jet', lw=0)
if plot_type == 'scatter':
x, y = m(lon,lat)
sc = m.scatter(x, y, c=data, cmap='jet', lw=0, s=4)
else:
# Create new arrays to add 1 additional longitude value to prevent a
# small amount of whitespace around longitude of 0/360 degrees.
lon_cyc = np.zeros((lon.shape[0],lon.shape[1]+1))
mask = np.zeros((data.shape[0],data.shape[1]+1))
lat_cyc = np.zeros((lat.shape[0],lat.shape[1]+1))

mask[:,0:-1] = data.mask[:,:]
mask[:,-1] = data.mask[:,0]
lon_cyc[:,0:-1] = lon[:,:]; lon_cyc[:,-1] = lon[:,0]
lat_cyc[:,0:-1] = lat[:,:]; lat_cyc[:,-1] = lat[:,0]

lon1 = np.ma.masked_array(lon_cyc, mask=mask)
lat1 = np.ma.masked_array(lat_cyc, mask=mask)

d = np.zeros((data.shape[0],data.shape[1]+1))
d[:,0:-1] = data[:,:]
d[:,-1] = data[:,0]
d1 = np.ma.masked_array(d,mask=mask)

x, y = m(lon1.data, lat1.data)

if plot_type == 'contour':
sc = m.contourf(x, y, d1, cmap='jet')
else: # pcolor
sc = m.pcolor(x, y, d1, cmap='jet')

m.drawparallels(np.arange(-90.,120.,15.),labels=[1,0,0,0]) # draw parallels
m.drawmeridians(np.arange(0.,420.,30.),labels=[1,1,1,1]) # draw meridians

# Plot the southern hemisphere data as a scatter plot
plt.sca(axes[1])
m = Basemap(projection='spstere', boundinglat=-45,lon_0=270, resolution='l')
m.drawcoastlines()
m.fillcontinents()
m.drawcountries()

if plot_type == 'scatter':
x, y = m(lon,lat)
sc = m.scatter(x, y, c=data, cmap='jet', lw=0, s=4)
else:
x, y = m(lon1.data, lat1.data)

m.drawmeridians(np.arange(0, 360, 60), labels=[0, 0, 0, 1], fontsize=10)
m.drawparallels(np.arange(-90, 90, 30), labels=[1, 0, 0, 0], fontsize=10)
# Bandaid for a bug in the version of Basemap used during development
outside = (x <= m.xmin) | (x >= m.xmax) | (y <= m.ymin) | (y >= m.ymax)
tmp = np.ma.masked_where(outside,d1)

plt.title('CICE Ice Thickness')
if plot_type == 'contour':
sc = m.contourf(x, y, tmp, cmap='jet')
else: # pcolor
sc = m.pcolor(x, y, tmp, cmap='jet')

# Create the colorbar and add Pass / Fail labels
divider = make_axes_locatable(ax)
cax = divider.append_axes("bottom", size="5%", pad=0.5)
cb = plt.colorbar(sc, cax=cax, orientation="horizontal", format="%.2f")
m.drawparallels(np.arange(-90.,120.,15.),labels=[1,0,0,0]) # draw parallels
m.drawmeridians(np.arange(0.,420.,30.),labels=[1,1,1,1]) # draw meridians

plt.suptitle('CICE Mean Ice Thickness\n{}'.format(case), y=0.95)

# Make some room at the bottom of the figure, and create a colorbar
fig.subplots_adjust(bottom=0.2)
cbar_ax = fig.add_axes([0.11,0.1,0.8,0.05])
cb = plt.colorbar(sc, cax=cbar_ax, orientation="horizontal", format="%.2f")
cb.set_label(units, x=1.0)

plt.savefig('ice_thickness_map.png', dpi=300)
outfile = 'ice_thickness_{}.png'.format(case.replace('\n- ','_minus_'))
logger.info('Creating map of the data ({})'.format(outfile))
plt.savefig(outfile, dpi=300, bbox_inches='tight')

def plot_two_stage_failures(data, lat, lon):
'''This function plots each grid cell and whether or not it Passed or Failed
Expand Down Expand Up @@ -428,7 +482,7 @@ def plot_two_stage_failures(data, lat, lon):
ax = fig.add_axes([0.05, 0.08, 0.9, 0.9])

# Create the basemap, and draw boundaries
m = Basemap(projection='kav7', lon_0=180., resolution='l')
m = Basemap(projection='moll', lon_0=0., resolution='l')
m.drawmapboundary(fill_color='white')
m.drawcoastlines()
m.drawcountries()
Expand All @@ -440,7 +494,7 @@ def plot_two_stage_failures(data, lat, lon):

# Plot the data as a scatter plot
x, y = m(lon, lat)
sc = m.scatter(x, y, c=int_data, cmap=cm, lw=0, vmin=0, vmax=1)
sc = m.scatter(x, y, c=int_data, cmap=cm, lw=0, vmin=0, vmax=1, s=4)

m.drawmeridians(np.arange(0, 360, 60), labels=[0, 0, 0, 1], fontsize=10)
m.drawparallels(np.arange(-90, 90, 30), labels=[1, 0, 0, 0], fontsize=10)
Expand Down Expand Up @@ -482,8 +536,11 @@ def main():
help='Path to the test history (iceh_inst*) files. REQUIRED')
parser.add_argument('-v', '--verbose', dest='verbose', help='Print debug output?', \
action='store_true')
parser.add_argument('-pt','--plot_type', dest='plot_type', help='Specify type of plot \
to create', choices=['scatter','contour','pcolor'])

parser.set_defaults(verbose=False)
parser.set_defaults(plot_type='pcolor')

# If no arguments are provided, print the help message
if len(sys.argv) == 1:
Expand Down Expand Up @@ -528,6 +585,17 @@ def main():
# If test failed, attempt to create a plot of the failure locations
if not PASSED:
plot_two_stage_failures(H1_array, t_lat, t_lon)

# Create plots of mean ice thickness
baseDir = os.path.abspath(args.base_dir).rstrip('history/').rstrip(\
'history').split('/')[-1]
testDir = os.path.abspath(args.test_dir).rstrip('history/').rstrip( \
'history').split('/')[-1]
plot_data(np.mean(data_base,axis=0), t_lat, t_lon, 'm', baseDir, args.plot_type)
plot_data(np.mean(data_test,axis=0), t_lat, t_lon, 'm', testDir, args.plot_type)
plot_data(np.mean(data_base-data_test,axis=0), t_lat, t_lon, 'm', '{}\n- {}'.\
format(baseDir,testDir), args.plot_type)

logger.error('Quality Control Test FAILED')
sys.exit(-1)

Expand Down Expand Up @@ -559,6 +627,16 @@ def main():

PASSED_SKILL = PASSED_NH and PASSED_SH

# Plot the ice thickness data for the base and test cases
baseDir = os.path.abspath(args.base_dir).rstrip('history/').rstrip( \
'history').split('/')[-1]
testDir = os.path.abspath(args.test_dir).rstrip('history/').rstrip( \
'history').split('/')[-1]
plot_data(np.mean(data_base,axis=0), t_lat, t_lon, 'm', baseDir, args.plot_type)
plot_data(np.mean(data_test,axis=0), t_lat, t_lon, 'm', testDir, args.plot_type)
plot_data(np.mean(data_base-data_test,axis=0), t_lat, t_lon, 'm', '{}\n- {}'.\
format(baseDir,testDir), args.plot_type)

logger.info('')
if not PASSED_SKILL:
logger.error('Quality Control Test FAILED')
Expand Down
10 changes: 8 additions & 2 deletions doc/source/user_guide/ug_testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ To install the necessary Python packages, the ``pip`` Python utility can be used
pip install --user matplotlib

To run the compliance test, setup a baseline run with the original baseline model and then
a perturbation run based on recent model changes. Use ``--sets qc`` in both runs in addition
a perturbation run based on recent model changes. Use ``--set qc`` in both runs in addition
to other settings needed. Then use the QC script to compare history output,

.. code-block:: bash
Expand All @@ -870,11 +870,17 @@ Implementation notes: 1) Provide a pass/fail on each of the confidence
intervals, 2) Facilitate output of a bitmap for each test so that
locations of failures can be identified.

The cice.t-test.py requires memory to store multiple two-dimensional fields spanning
The ``cice.t-test.py`` requires memory to store multiple two-dimensional fields spanning
1825 unique timesteps, a total of several GB. An appropriate resource is needed to
run the script. If the script runs out of memory on an interactive resource, try
logging into a batch resource or finding a large memory node.

The ``cice.t-test.py`` script will also attempt to generate plots of the mean ice thickness
for both the baseline and test cases. Additionally, if the 2-stage test fails then the
script will attempt to plot a map showing the grid cells that failed the test. For a
full list of options, run ``python cice.t-test.py -h``.



End-To-End Testing Procedure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down