diff --git a/arm_diags/.DS_Store b/arm_diags/.DS_Store index 96c4b32..660471e 100644 Binary files a/arm_diags/.DS_Store and b/arm_diags/.DS_Store differ diff --git a/arm_diags/arm_driver.py b/arm_diags/arm_driver.py index b8f6ab7..ddbf317 100644 --- a/arm_diags/arm_driver.py +++ b/arm_diags/arm_driver.py @@ -4,6 +4,7 @@ import numpy import cdutil import genutil +import shutil import cdms2 import MV2 import glob @@ -20,13 +21,18 @@ from src.pdf_daily import pdf_daily_data, pdf_daily_plot # .src from src.convection_onset_driver import convection_onset # .src from src.aerosol_activation import aerosol_activation_density_plot # .src -#from src.convection_onset_driver_todd import convection_onset -from src.create_htmls import annual_cycle_zt_html,diurnal_cycle_zt_html,diurnal_cycle_html,seasonal_mean_table_html,annual_cycle_html,annual_cycle_aci_html,pdf_daily_html,convection_onset_html,aerosol_activation_html,diags_main_html +from src.twolegged_metric import twolegged_metric_plot # .src +from src.diurnal_cycle_LAcoupling import diurnal_cycle_LAcoupling_plot +#from src.convection_onset_driver_todd import convection_onset +from src.create_htmls import annual_cycle_zt_html,diurnal_cycle_zt_html,diurnal_cycle_html,seasonal_mean_table_html,annual_cycle_html,annual_cycle_aci_html,pdf_daily_html,convection_onset_html,aerosol_activation_html,twolegged_metric_html,diurnal_cycle_LAcoupling_html,diags_main_html def make_parameters(basic_parameter): #f_data = open('examples/diags_set3.json').read() #f_data = open('diags_all_multisites_for_cmip5.json').read() f_data = open('diags_all_multisites_for_cmip6.json').read() + #f_data = open('diags_set10_cmip6.json').read() + #f_data = open('diags_all_multisites_for_LAcoupling.json').read() + #f_data = open('diags_all_multisites_check.json').read() json_file = json.loads(f_data) parameters = [] @@ -48,9 +54,10 @@ def make_parameters(basic_parameter): #basic_parameter = parser.get_parameters() parameters = make_parameters(basic_parameter) - case_id = basic_parameter.case_id output_path = basic_parameter.output_path +armdiags_path = basic_parameter.armdiags_path +print('output_path: ',output_path) # Generate new case folder given case_id: if not os.path.exists(os.path.join(output_path)): @@ -59,6 +66,13 @@ def make_parameters(basic_parameter): os.makedirs(os.path.join(output_path,'figures')) os.makedirs(os.path.join(output_path,'metrics')) +# Copy the logo figures to the newly created html folder +src = os.listdir(armdiags_path+'arm_diags/misc/') +dst = output_path+'/html/' +for ifile in range(len(src)): + src1 = armdiags_path+'arm_diags/misc/'+src[ifile] + shutil.copy(src1, dst) + # Loop through diagnostic sets prespecified from diags_sets.json html_count = 0 for parameter in parameters: @@ -138,7 +152,18 @@ def make_parameters(basic_parameter): html_count = html_count + 1 #except: #pass - + + if diags_set == 'set10_twolegged_metric': + twolegged_metric_plot(parameter) + twolegged_metric_html(parameter) + html_count = html_count + 1 + + if diags_set == 'set11_diurnal_cycle_LAcoupling': + diurnal_cycle_LAcoupling_plot(parameter) + diurnal_cycle_LAcoupling_html(parameter) + html_count = html_count + 1 + + # if html_count >= 1: # Creat the main html page hosting all sets of diagnostics diff --git a/arm_diags/basicparameter.py b/arm_diags/basicparameter.py index 0ff8a73..659c62f 100644 --- a/arm_diags/basicparameter.py +++ b/arm_diags/basicparameter.py @@ -5,7 +5,11 @@ #--------------------------------------------------------------------------------------------------------------------------- #=========================================================================================================================== # User defined case id -case_id = 'V3_TestCMIP6' +#case_id = 'output_cheng_20230705_mdtfv3_cesm' +case_id = 'output_cheng_20240905_armdiags_v4' + +# User defined the ARM-Diags package path +armdiags_path = '/Users/tao4/Documents/ARM_Infrastructure/ARM_DIAG/arm-gcm-diagnostics/' #-------------------------------------------------------------------------- # Testing model dataset (User defined model) @@ -13,20 +17,27 @@ test_data_set = 'testmodel' #specify the data starting/ending years in the testmodel file #default is 1979 - 2006 as in the CMIP file -test_start_year = 1979 + +#NCAR: 2013, 2014 +#GFDL: 1980, 2000 +test_start_year = 1979 test_end_year = 2006 #-------------------------------------------------------------------------- # Set input path, where the model, observational and cmip data are located. -base_path = '/DATA/ARM-Diag/arm-gcm-diagnostics/arm_diags/' - +#base_path = '/DATA/ARM-Diag/arm-gcm-diagnostics/arm_diags/' +#base_path = '/Users/tao4/Documents/ARM_Infrastructure/ARM_DIAG/arm_diags_data_v3.1_07052023_mdtfv3_cesm/' +#base_path = '/Users/tao4/Documents/ARM_Infrastructure/ARM_DIAG/arm_diags_data_v3.1_05192023/' +#base_path = '/Users/tao4/Documents/ARM_Infrastructure/ARM_DIAG/arm_diags_data_v3.1_06292023_mdtfv3_gfdl/' +base_path = '/Users/tao4/Documents/ARM_Infrastructure/ARM_DIAG/arm_diags_data_v3.1_06122023/' test_data_path = base_path+'testmodel' obs_path = base_path+'observation' cmip_path = base_path+'cmip6' #-------------------------------------------------------------------------- # Set output path, where the results will be saved -output_path = '/DATA/ARM-Diag/Results/'+case_id +#output_path = '/DATA/ARM-Diag/Results/'+case_id +output_path = '/Users/tao4/Documents/ARM_Infrastructure/ARM_DIAG/'+case_id arm_filename = True #=========================================================================================================================== diff --git a/arm_diags/diags_all_multisites_for_cmip6.json b/arm_diags/diags_all_multisites_for_cmip6.json index b4b36f9..afee4ff 100644 --- a/arm_diags/diags_all_multisites_for_cmip6.json +++ b/arm_diags/diags_all_multisites_for_cmip6.json @@ -283,7 +283,22 @@ "diags_set": "set9_aerosol_activation", "variables": ["cpc","ccn"], "sites": ["enac1"] + }, + { + "diags_set": "set10_twolegged_metric", + "variables": ["Atmospheric Coupling Legs","Terrestrial Cooupling Legs"], + "sites": ["sgpc1"], + "season": ["DJF","MAM","JJA","SON"] + }, + { + "diags_set": "set11_diurnal_cycle_LAcoupling", + "variables": ["SH","LH","T_srf","RH_srf","LCL","pbl"], + "varnames": ["Surface Sensible Heat Flux","Surface Latent Heat Flux","Surface Air Temperature","Surface Relative Humidity","Lifting Condensation Level","Planatary Boundary Layer"], + "units": ["W/m\u00b2","W/m\u00b2","deg C","%","meter","meter"], + "sites": ["sgpc1"], + "season": ["ANN","DJF","MAM","JJA","SON"] } + ] } diff --git a/arm_diags/src/annual_cycle_zt.py b/arm_diags/src/annual_cycle_zt.py index aa49127..05794d8 100644 --- a/arm_diags/src/annual_cycle_zt.py +++ b/arm_diags/src/annual_cycle_zt.py @@ -344,8 +344,10 @@ def annual_cycle_zt_plot(parameter): if test_findex == 1: ct_up=np.nanmax([cl_ob,cl_p]) tmpct=cl_p[:,::-1]-cl_ob[:,::-1] - ct_lo_diff=np.int(np.nanmin(tmpct)-1) - ct_up_diff=np.int(np.nanmax(tmpct)+1) + + ct_lo_diff=int(np.nanmin(tmpct)-1) + ct_up_diff=int(np.nanmax(tmpct)+1) + rlevel=np.arange(ct_lo,ct_up+1,0.5) #original drlevel=np.arange(ct_lo_diff,ct_up_diff,0.5) #difference #---------------------------------------------- diff --git a/arm_diags/src/convection_onset_driver.py b/arm_diags/src/convection_onset_driver.py index b875522..7385545 100644 --- a/arm_diags/src/convection_onset_driver.py +++ b/arm_diags/src/convection_onset_driver.py @@ -86,10 +86,10 @@ def convection_onset(parameter): else: filename = glob.glob(os.path.join(obs_path,site[:3]+'armdiags1hr' + site[3:5].upper()+'*.nc'))[0] - print(filename) + print('filename: ',filename) f_in=cdms2.open(filename) var=f_in(va) - print('var_shape',va,var.shape) + print('var_shape: ',va,var.shape) if va == 'pr': precip = var precip[precip<-900] = np.nan diff --git a/arm_diags/src/convection_onset_statistics.py b/arm_diags/src/convection_onset_statistics.py index aa56942..bfebbdf 100644 --- a/arm_diags/src/convection_onset_statistics.py +++ b/arm_diags/src/convection_onset_statistics.py @@ -70,13 +70,14 @@ def convection_onset_statistics(precip_threshold,cwv_max,cwv_min,bin_width,cwv,p #cwv_max = 85 # default = 70 (in mm) #cwv_min = 28 # default = 28 (in mm) #bin_width = 1.5 # default = 1.5 + #print('inputs: ',cwv_max,cwv_min,bin_width) number_of_bins = int(np.ceil((cwv_max-cwv_min)/bin_width)) - #print('cwv_max',cwv_max) - #print(number_of_bins) + #print('number_of_bins: ',number_of_bins) bin_center = np.arange((cwv_min+(bin_width/2)), (cwv_max-(bin_width/2))+bin_width, bin_width) #print('bin_center',bin_center,'bin_width',bin_width) if len(bin_center)!=number_of_bins: bin_center = np.arange((cwv_min+(bin_width/2)), (cwv_max-(bin_width/2)), bin_width) + #print('bin_center range: ',np.min(bin_center),np.max(bin_center)) # Define precip threshold #precip_threshold = 0.5 # default 0.5 (in mm/hr) @@ -86,8 +87,14 @@ def convection_onset_statistics(precip_threshold,cwv_max,cwv_min,bin_width,cwv,p precip_binned = np.empty([number_of_bins,cwv.size]) * np.nan precip_counts = np.zeros([number_of_bins,cwv.size]) - np.warnings.filterwarnings('ignore') + #============================================ + # Cheng 09/05/2024 + # Comment out the following line. + # Otherwise, the figures cannot be generated + #========================================== + #np.warnings.filterwarnings('ignore') # Bin the data by CWV value as specified above + print("Bin the data by CWV value as specified above") for i in range (0,number_of_bins): tmp1 = np.where(cwv > cwv_min+(i*bin_width)) bin_index[i,tmp1] = 1 @@ -116,6 +123,7 @@ def convection_onset_statistics(precip_threshold,cwv_max,cwv_min,bin_width,cwv,p # precip_counts[i,j] = 1 if np.isnan(precip_binned[i,j]): precip_counts[i,j] = np.nan + #print('Check') # Create binned arrays hist_cwv = np.empty([number_of_bins,1]) * np.nan @@ -175,19 +183,19 @@ def convection_onset_statistics(precip_threshold,cwv_max,cwv_min,bin_width,cwv,p xulim = 5*np.ceil(np.max(np.round(bin_center+bin_width/2))/5) xllim = 5*np.floor(np.min(np.round(bin_center-bin_width/2))/5) ax1.set_xlim(xllim-10,xulim+15) - ax1.set_ylim(0,5) + #ax1.set_ylim(0,5) ax1.set_xticks(np.arange(np.ceil(xllim/10)*10-10,np.ceil(xulim/10)*10+15,15)) #print(np.arange(np.ceil(xllim/10)*10-10,np.ceil(xulim/10)*10+15,15)) #print(np.ceil(xllim/10)*10) #print(np.ceil(xulim/10)*10) ulim = np.nanmax(pr_binned_mean) #print('max precip',ulim) - #ax1.set_yticks(np.arange(0,np.ceil(ulim))) - ax1.set_yticks(np.arange(0,5)) + ax1.set_yticks(np.arange(0,np.ceil(ulim))) + #ax1.set_yticks(np.arange(0,5)) #ax1.set_xlim(25,72) #ax1.set_ylim(0,6) #ax1.set_xticks([30,40,50,60,70]) - #ax1.set_yticks([0,1,2,3,4,5,6]) + ax1.set_yticks([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]) ax1.tick_params(labelsize=axes_fontsize) ax1.tick_params(axis='x', pad=10) error = [errorbar_precip,errorbar_precip] diff --git a/arm_diags/src/create_htmls.py b/arm_diags/src/create_htmls.py index f84d760..ec9930c 100644 --- a/arm_diags/src/create_htmls.py +++ b/arm_diags/src/create_htmls.py @@ -1,11 +1,11 @@ #=========================================================================================================================== # Program for generate the HTML files hosting the results -- Original written by Dr. Chengzhu Zhang @ LLNL #--------------------------------------------------------------------------------------------------------------------------- -# V3 Development +# V4 Development # --------------------------------------------------------------------------------------- - # Xiaojian Zheng - Dec 2021 - # ### change the input/output format to site-dependent (ENA/MAO added) - # ### fix minor issues on image linking + # Cheng Tao - Jul, 2024 + # ### Edit the name of some of metrics + # ### Fix the links of sampled figures # --------------------------------------------------------------------------------------- #=========================================================================================================================== import csv @@ -28,13 +28,13 @@ def diags_main_html(output_path,test_model):

- ARM data-oriented Diagnostics package (ARM-DIAGS-V3) + ARM data-oriented Diagnostics package (ARM-DIAGS-V4)

Metrics and Diagnostics

Model: """+test_model+"""


- +
@@ -44,36 +44,39 @@ def diags_main_html(output_path,test_model):

2 Line plots and Taylor diagrams of Annual Cycle.

- 3 Line plots and Taylor diagrams of ACI Annual Cycle.
+ 3 Line plots and Taylor diagrams of Aerosol-Cloud Interaction Annual Cycle.

- 4 Contour and Vertical profiles of Annual Cycle.
+ 4 Contour and Vertical profiles of Cloud Fraction Annual Cycle.

- 5 Line and Harmonic Dail plots of Diurnal Cycle.
+ 5 Line and Harmonic Dail plots of Precipitation Diurnal Cycle.

- 6 Contour plots of Diurnal Cycle.
+ 6 Contour plots of Cloud Fraction Diurnal Cycle.

7 Line plots of Probability Density Function.
+

+ 8 Line plots of Land-Atmosphere Coupling Diurnal Cycle.

- + Process-oriented Diagnostics Sets

1 Basic diagnostics plots for Convection Onset.

2 Basic diagnostics plots for Aerosol Activation.
- +

+ 3 Basic diagnostics plots for Two-legged metrics.

Click on Plot Type

- Set 1 - Set 1 - Set 3 - Set 3 - Set 4 - Set 6 + Set 1 + Set 1 + Set 3 + Set 3 + Set 4 + Set 6 @@ -83,7 +86,7 @@ def diags_main_html(output_path,test_model):

- +
@@ -196,8 +199,8 @@ def annual_cycle_html(parameter): htmlfile.write(''+var_longname[j]) two_figs='annual_cycle_'+variable+'_2plots_{}.html'.format(title_name) htmlfile1 = open(output_path+'/html/'+two_figs,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+variable+'_annual_cycle_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+variable+'_annual_cycle_taylor_diagram_{}.png'.format(title_name) + fig1='../figures/{}/'.format(title_name)+variable+'_annual_cycle_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+variable+'_annual_cycle_taylor_diagram_{}.png'.format(title_name) htmlfile1.write('

Line
Line
') htmlfile.write('Line plot and Taylor Diagram.') htmlfile.write('
') @@ -232,8 +235,10 @@ def annual_cycle_aci_html(parameter): htmlfile.write(''+var_longname[j]) two_figs='annual_cycle_'+variable+'_2plots_{}.html'.format(title_name) htmlfile1 = open(output_path+'/html/'+two_figs,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+'aerosol_annual_cycle_'+variable+'_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+'aerosol_annual_cycle_'+variable+'_taylor_diagram_{}.png'.format(title_name) + + fig1='../figures/{}/'.format(title_name)+'aerosol_annual_cycle_'+variable+'_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+'aerosol_annual_cycle_'+variable+'_taylor_diagram_{}.png'.format(title_name) + htmlfile1.write('
Line
Line
') htmlfile.write('Line plot and Taylor Diagram.') htmlfile.write('
') @@ -273,16 +278,18 @@ def annual_cycle_zt_html(parameter): htmlfile.write(''+var_longname[j])#+'('+vas_source[va_ind]+')') title_name = title_to_file[title] - fig_obs=output_path+'/figures/{}/'.format(title_name)+variable+'_annual_cycle_clim_obs_{}.png'.format(title_name) - fig_mod=output_path+'/figures/{}/'.format(title_name)+variable+'_annual_cycle_clim_mod_{}.png'.format(title_name) - fig_diff=output_path+'/figures/{}/'.format(title_name)+variable+'_annual_cycle_clim_the_diff_{}.png'.format(title_name) + fig_obs='../figures/{}/'.format(title_name)+variable+'_annual_cycle_clim_obs_{}.png'.format(title_name) + fig_mod='../figures/{}/'.format(title_name)+variable+'_annual_cycle_clim_mod_{}.png'.format(title_name) + fig_diff='../figures/{}/'.format(title_name)+variable+'_annual_cycle_clim_the_diff_{}.png'.format(title_name) + htmlfile.write(' Model ') htmlfile.write(' Obs.') htmlfile.write(' Model-Obs.') #htmlfile.write('
') for si in range(len(seasons)): - fig=output_path+'/figures/{}/'.format(title_name)+variable+'_zdiff_'+seasons[si]+'_{}.png'.format(title_name) + fig='../figures/{}/'.format(title_name)+variable+'_zdiff_'+seasons[si]+'_{}.png'.format(title_name) + if seasons[si]=='ANN': htmlfile.write(' '+seasons[si]+'') else: @@ -320,13 +327,15 @@ def diurnal_cycle_html(parameter): # Create the HTML file for output #htmlfile.write('
') htmlfile.write(''+var_longname[j]) + for season in seasons: two_figs='diurnal_cycle_'+variable+'_'+season+'_2plots_{}.html'.format(title_name) htmlfile1 = open(output_path+'/html/'+two_figs,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+variable+'_'+season+'_diurnal_cycle_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+variable+'_'+season+'_diurnal_cycle_harmonic_diagram_{}.png'.format(title_name) + fig1='../figures/{}/'.format(title_name)+variable+'_'+season+'_diurnal_cycle_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+variable+'_'+season+'_diurnal_cycle_harmonic_diagram_{}.png'.format(title_name) htmlfile1.write('
Line
Line
') - htmlfile.write(''+season+'.') + htmlfile.write(''+season+'.') + htmlfile.write('
') #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -358,10 +367,11 @@ def diurnal_cycle_zt_html(parameter): for j, variable in enumerate(variables): #for va_ind in range(len(vas)-2):# at this stage for cl_p only htmlfile.write(''+var_longname[j])#+'('+vas_source[va_ind]+')') - fig_obs=output_path+'/figures/{}/'.format(title_name)+variable+'_diurnal_clim_obs_{}.png'.format(title_name) - fig_mod=output_path+'/figures/{}/'.format(title_name)+variable+'_diurnal_clim_mod_{}.png'.format(title_name) - fig_obs_mon=output_path+'/figures/{}/'.format(title_name)+variable+'_mon_diurnal_clim_obs_{}.png'.format(title_name) - fig_mod_mon=output_path+'/figures/{}/'.format(title_name)+variable+'_mon_diurnal_clim_mod_{}.png'.format(title_name) + fig_obs='../figures/{}/'.format(title_name)+variable+'_diurnal_clim_obs_{}.png'.format(title_name) + fig_mod='../figures/{}/'.format(title_name)+variable+'_diurnal_clim_mod_{}.png'.format(title_name) + fig_obs_mon='../figures/{}/'.format(title_name)+variable+'_mon_diurnal_clim_obs_{}.png'.format(title_name) + fig_mod_mon='../figures/{}/'.format(title_name)+variable+'_mon_diurnal_clim_mod_{}.png'.format(title_name) + htmlfile.write(' Model ') htmlfile.write(' Obs.') htmlfile.write(' Model ') @@ -403,10 +413,10 @@ def pdf_daily_html(parameter): for season in seasons: two_figs='pdf_daily_'+variable+'_'+season+'_2plots_{}.html'.format(title_name) htmlfile1 = open(output_path+'/html/'+two_figs,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+variable+'_'+season+'_pdf1_daily_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+variable+'_'+season+'_pdf2_daily_{}.png'.format(title_name) + fig1='../figures/{}/'.format(title_name)+variable+'_'+season+'_pdf1_daily_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+variable+'_'+season+'_pdf2_daily_{}.png'.format(title_name) htmlfile1.write('
Line
Line
') - htmlfile.write(''+season+'.') + htmlfile.write(''+season+'.') htmlfile.write('
') #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -436,9 +446,9 @@ def convection_onset_html(parameter): two_figs='convection_onset_'+title_name+'_2plots.html' htmlfile1 = open(output_path+'/html/'+two_figs,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+'conv_diagnostics_ARM_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+'conv_diagnostics_{}_{}.png'.format(test_model, title_name) - htmlfile1.write('
Line
Line
') + fig1='../figures/{}/'.format(title_name)+'conv_diagnostics_ARM_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+'conv_diagnostics_{}_{}.png'.format(test_model, title_name) + htmlfile1.write('
Line
No inputs for models
') htmlfile.write(''+'Obs vs. Model'+'') #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= @@ -460,17 +470,97 @@ def aerosol_activation_html(parameter): #ccn02 two_figs_02='aerosol_activation_ccn02_'+title_name+'_2plots.html' htmlfile_02 = open(output_path+'/html/'+two_figs_02,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn02_obs_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn02_testmodel_{}.png'.format(title_name) - htmlfile_02.write('
Line
Line
') + fig1='../figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn02_obs_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn02_testmodel_{}.png'.format(title_name) + htmlfile_02.write('
Line
No inputs for models
') #ccn05 two_figs_05='aerosol_activation_ccn05_'+title_name+'_2plots.html' htmlfile_05 = open(output_path+'/html/'+two_figs_05,"w") - fig1=output_path+'/figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn05_obs_{}.png'.format(title_name) - fig2=output_path+'/figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn05_testmodel_{}.png'.format(title_name) - htmlfile_05.write('
Line
Line
') + fig1='../figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn05_obs_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+'aerosol_activation_bulk_cpc_ccn05_testmodel_{}.png'.format(title_name) + htmlfile_05.write('
Line
No inputs for models
') + # htmlfile.write(''+'At 0.2% SS'+'') htmlfile.write(''+'At 0.5% SS'+'') htmlfile.write('
') + #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +def twolegged_metric_html(parameter): + """Create set 4 diag. html hosting two-legged metrics for 4 seasons""" + output_path = parameter.output_path + test_model = parameter.test_data_set + seasons = parameter.season + variables = parameter.variables + sites = parameter.sites + + title_to_file = OrderedDict() + title_to_file['Southern Great Plains (SGP)'] = 'sgpc1' + + htmlfile = open(output_path+'/html/twolegged_metric.html',"w") + htmlfile.write('

'+test_model+': Two-legged metric'+ '

') + htmlfile.write('') + + for title in title_to_file: + title_name = title_to_file[title] + htmlfile.write(''.format(title)) + for j, variable in enumerate(variables): + # Create the HTML file for output + htmlfile.write('') + +#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +def diurnal_cycle_LAcoupling_html(parameter): + output_path = parameter.output_path + test_model = parameter.test_data_set + seasons = parameter.season + variables = parameter.variables + varnames = parameter.varnames + units = parameter.units + sites = parameter.sites + + title_to_file = OrderedDict() + title_to_file['Southern Great Plains (SGP)'] = 'sgpc1' + + htmlfile = open(output_path+'/html/diurnal_cycle_LAcoupling.html',"w") + htmlfile.write('

') + htmlfile.write('

{}
'+variables[j]+' (Obs. vs. Model)') + + for season in seasons: + #Atmospheric component + two_figs_atm = 'twolegged_metric_atm_'+season+'_'+title_name+'.html' + htmlfile_atm = open(output_path+'/html/'+two_figs_atm,"w") + fig1='../figures/{}/'.format(title_name)+'Scatter_plot_'+season+'_atmos_component_obs_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+'Scatter_plot_'+season+'_atmos_component_testmod_{}.png'.format(title_name) + #print(fig2) + + htmlfile_atm.write('
Line
No inputs for models
') + + #Terrestrial component + two_figs_land = 'twolegged_metric_land_'+season+'_'+title_name+'.html' + htmlfile_land = open(output_path+'/html/'+two_figs_land,"w") + fig1='../figures/{}/'.format(title_name)+'Scatter_plot_'+season+'_land_component_obs_{}.png'.format(title_name) + fig2='../figures/{}/'.format(title_name)+'Scatter_plot_'+season+'_land_component_testmod_{}.png'.format(title_name) + htmlfile_land.write('
Line
No inputs for models
') + + if j==0: + htmlfile.write('
'+season+'') + elif j==1: + htmlfile.write(''+season+'') + + htmlfile.write('

'+test_model+': Land-Atmosphere Coupling Diurnal Cycle'+ '
') + + for title in title_to_file: + title_name = title_to_file[title] + htmlfile.write(''.format(title)) + for j, variable in enumerate(variables): + # Create the HTML file for output + htmlfile.write('') diff --git a/arm_diags/src/diurnal_cycle.py b/arm_diags/src/diurnal_cycle.py index 0e8c44b..d5dc8dd 100644 --- a/arm_diags/src/diurnal_cycle.py +++ b/arm_diags/src/diurnal_cycle.py @@ -113,6 +113,7 @@ def diurnal_cycle_data(parameter): print(test_path,test_model,sites[0][:3]+test_model+'*hr' + sites[0][3:5].upper()) test_file = glob.glob(os.path.join(test_path,sites[0][:3]+test_model+'*hr' + sites[0][3:5].upper()+'*.nc' )) + if len(test_file) == 0: print('No diurnal data for test model were found: '+sites[0]) @@ -123,6 +124,7 @@ def diurnal_cycle_data(parameter): #initialize the indicator for temporal res of testmodel test_tres = test_file[0].split(test_model)[-1][:3] #e.g., '3hr', '1hr' + fin = cdms2.open(test_file[0]) if test_tres == '1hr': test_tidlen=24 if test_tres == '3hr': test_tidlen=8 @@ -142,6 +144,7 @@ def diurnal_cycle_data(parameter): print((variable+" "+season+" not processed for " + test_model)) print('!!please check the start and end year in basicparameter.py') test_findex = 0 + # Calculate for observational data obs_var_season=np.empty([len(variables),24,len(seasons)])*np.nan #obs_file = glob.glob(os.path.join(obs_path,'*ARMdiag_domain_diurnal*.nc')) #read in diurnal test data @@ -225,6 +228,7 @@ def diurnal_cycle_data(parameter): os.makedirs(os.path.join(output_path,'metrics',sites[0])) for j, variable in enumerate(variables): for k, season in enumerate(seasons): + if test_findex == 1: np.savetxt(output_path+'/metrics/'+sites[0]+'/'+variable+'_'+season+'_test_diurnal_cycle_'+test_tres+'_'+sites[0]+'.csv',test_var_season[j,:,k]) np.savetxt(output_path+'/metrics/'+sites[0]+'/'+variable+'_'+season+'_mmm_diurnal_cycle_'+sites[0]+'.csv',mmm_var_season[j,:,k]) np.savetxt(output_path+'/metrics/'+sites[0]+'/'+variable+'_'+season+'_cmip_diurnal_cycle_'+sites[0]+'.csv',cmip_var_season[:,j,:,k]) diff --git a/arm_diags/src/diurnal_cycle_LAcoupling.py b/arm_diags/src/diurnal_cycle_LAcoupling.py new file mode 100644 index 0000000..774b2b4 --- /dev/null +++ b/arm_diags/src/diurnal_cycle_LAcoupling.py @@ -0,0 +1,155 @@ +#=========================================================================================================================== +# Program for generate the diurnal cycle on Land-Atmosphere Coupling +#--------------------------------------------------------------------------------------------------------------------------- +# V4 Development + # ---------------------------------------------------------------------------------------------------- + # Cheng Tao - Jul2024 @ LLNL + # ### Diurnal cycle of SH, LH, T_srf, RH_srf, LCL, PBL + # ---------------------------------------------------------------------------------------------------- +#=========================================================================================================================== +import os +import pdb +import glob +import cdms2 +import cdutil +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.gridspec import GridSpec +from .varid_dict import varid_longname +from .taylor_diagram import TaylorDiagram +from .utils import climo +from .utils import get_diurnal_cycle_seasons +import MV2 +import matplotlib.gridspec as gridspec +import scipy.stats +from scipy import interpolate +import calendar +import math + +def diurnal_cycle_LAcoupling_plot(parameter): + variables = parameter.variables + test_path = parameter.test_data_path + test_model = parameter.test_data_set + obs_path = parameter.obs_path + cmip_path = parameter.cmip_path + output_path = parameter.output_path + sites = parameter.sites + varnames = parameter.varnames + units = parameter.units + seasons = parameter.season + nseasons = len(seasons) + nvariables = len(variables) + + print('test_path: ',test_path) + + if not os.path.exists(os.path.join(output_path,'figures',sites[0])): + os.makedirs(os.path.join(output_path,'figures',sites[0])) + + #========================================================================== + # Calculate for test model data + #========================================================================== + test_file = glob.glob(os.path.join(test_path,sites[0][:3]+'testmodel3hrLAcoupling'+sites[0][3:5].upper()+'*.nc' )) + print('Processing test_file: ',test_file) + fin1 = cdms2.open(test_file[0]) + + #========================================================================== + # Calculate for observational data + #========================================================================== + print('ARM data',sites[0]) + obs_file = glob.glob(os.path.join(obs_path,sites[0][:3]+'armdiagsLAcoupling' + sites[0][3:5].upper()+'*c1.nc')) #read in data + print('Processing obs_file',obs_file) + fin = cdms2.open(obs_file[0]) + + for ivar in range(nvariables): + #============================ + # Seasons: for observations + #============================ + var = fin(variables[ivar]) + years_obs = list(range(2004,2016)) + nyears_obs = len(years_obs) + + #var_seasons = get_seasonal(var,seasons,years_obs) #[year,season,90,24] + var_seasons = get_diurnal_cycle_seasons(var,seasons,years_obs) + narray = nyears_obs*365 + var_seasons1 = np.empty([nseasons,narray,24])*np.nan + var_array_err = np.empty([nseasons,24])*np.nan + var_array = np.empty([nseasons,24])*np.nan + for iseason in range(nseasons): + for iyear in range(nyears_obs): + for iday in range(365): + var_seasons1[iseason,365*iyear+iday,:] = var_seasons[iyear,iseason,iday,:] + + array_tmp = var_seasons1[iseason,:,:] + data0 = np.nanstd(array_tmp,axis=0) #stddev + var_array_err[iseason,:] = data0/(math.sqrt(narray)) + var_array[iseason,:] = np.nanmean(array_tmp,axis=0) + + #========================== + # Seasons: for models + #========================== + try: + var_mod = fin1(variables[ivar]) + years_mod = list(range(2003,2015)) + nyears_mod = len(years_mod) + + #var_mod_seasons = get_seasonal_3hr(var_mod,seasons,years_mod) #[year,season,90,24] + var_mod_seasons = get_diurnal_cycle_seasons(var_mod,seasons,years_mod) + narray = nyears_mod*365 + var_mod_seasons1 = np.empty([nseasons,narray,8])*np.nan + var_mod_array_err = np.empty([nseasons,8])*np.nan + var_mod_array = np.empty([nseasons,8])*np.nan + for iseason in range(nseasons): + for iyear in range(nyears_mod): + for iday in range(365): + var_mod_seasons1[iseason,365*iyear+iday,:] = var_mod_seasons[iyear,iseason,iday,:] + + array_tmp = var_mod_seasons1[iseason,:,:] + data0 = np.nanstd(array_tmp,axis=0) #stddev + var_mod_array_err[iseason,:] = data0/(math.sqrt(narray)) + var_mod_array[iseason,:] = np.nanmean(array_tmp,axis=0) + except: + var_mod_array_err = np.empty([nseasons,8])*np.nan + var_mod_array = np.empty([nseasons,8])*np.nan + + #========================================================================== + # Plotting: Diurnal cycle (daytime) + #========================================================================== + for iseason in range(nseasons): + fig = plt.figure(figsize=[8,4], dpi=100) + xax = np.array([x for x in range(26)])-0.5 + y_data = np.empty([26])*np.nan + y_data[0:19] = var_array[iseason,5:24] + y_data[19:26] = var_array[iseason,0:7] + + e_data = np.empty([26])*np.nan + e_data[0:19] = var_array_err[iseason,5:24] + e_data[19:26] = var_array_err[iseason,0:7] + plt.errorbar(xax,y_data,e_data,color='black',label='OBS',linewidth=2) + + + if variables[ivar]=='SH' or variables[ivar]=='LH': + xax1 = np.array([x for x in range(10)])*3-1.5 + else: + xax1 = np.array([x for x in range(10)])*3-3.0 + y1_data = np.empty([10])*np.nan + y1_data[0:7] = var_mod_array[iseason,1:8] + y1_data[7:10] = var_mod_array[iseason,0:3] + + e1_data = np.empty([10])*np.nan + e1_data[0:7] = var_mod_array_err[iseason,1:8] + e1_data[7:10] = var_mod_array_err[iseason,0:3] + plt.errorbar(xax1,y1_data,e1_data,color='red',label='MOD',linewidth=2) + + plt.ylabel(units[ivar],fontsize=12) + plt.title(variables[ivar]+' ('+seasons[iseason]+')',fontsize=14) + plt.xticks([0,2,4,6,8,10,12,14,16,18,20,22,24],\ + ["0","2","4","6","8","10","12","14","16","18","20","22","24"]) + plt.xlabel('LST (hour)',fontsize=12) + plt.xlim([-0.1,24.1]) + if variables[ivar]=='pbl': + plt.xlim([7.4,17.6]) + plt.legend() + plt.savefig(output_path+'/figures/'+sites[0]+'/'+'Diurnal_cycle_'+seasons[iseason]+'_'+variables[ivar]+'_'+sites[0]+'.png') + + + fin.close() diff --git a/arm_diags/src/pdf_daily.py b/arm_diags/src/pdf_daily.py index f7fef55..3f2689a 100644 --- a/arm_diags/src/pdf_daily.py +++ b/arm_diags/src/pdf_daily.py @@ -431,3 +431,4 @@ def pdf_daily_plot(parameter): # # # + diff --git a/arm_diags/src/twolegged_metric.py b/arm_diags/src/twolegged_metric.py new file mode 100644 index 0000000..1081e39 --- /dev/null +++ b/arm_diags/src/twolegged_metric.py @@ -0,0 +1,425 @@ +#=========================================================================================================================== +# Program for generate the two-legged metrics: Terrestrial and Atmospheric Coupling Legs +#--------------------------------------------------------------------------------------------------------------------------- +# V4 Development + # ---------------------------------------------------------------------------------------------------- + # Cheng Tao - Jul2024 @ LLNL + # ### Scatter plot of soil moisture vs. SH/LH/EF + # ### Scatter plot of SH/LH/EF vs. LCL + # ---------------------------------------------------------------------------------------------------- + +#=========================================================================================================================== +import os +import pdb +import glob +import cdms2 +import cdutil +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.gridspec import GridSpec +from .varid_dict import varid_longname +from .taylor_diagram import TaylorDiagram +from .utils import climo +import MV2 +import matplotlib.gridspec as gridspec +import scipy.stats +from scipy import interpolate +import calendar + +def get_seasonal_data_3hr(var,seasons,years): + + '''Get seasonal data for each variable''' + nyears = len(years) + nseasons = len(seasons) + nsteps = int(nyears*90) + t0 = 0 + + var_seasons = MV2.zeros([nyears,nseasons,90])*np.nan #Daily mean for each season + var_seasons_f = MV2.zeros([nsteps,nseasons])*np.nan + for iyear in range(nyears): + if calendar.isleap(int(years[iyear]))==True: + nday = 366 + else: + nday = 365 + ntime = int(nday*8) + var1 = var[t0:t0+ntime] + var1_ext = np.concatenate((var1,var1),axis=0) + t0 = t0+ntime + + for iseason in range(nseasons): + if seasons[iseason]=='MAM': + if nday==366: t1 = 60 + else: t1 = 59 + if seasons[iseason]=='JJA': + if nday==366: t1 = 152 + else: t1 = 151 + if seasons[iseason]=='SON': + if nday==366: t1 = 244 + else: t1 = 243 + if seasons[iseason]=='DJF': + if nday==366: t1 = 335 + else: t1 = 334 + var_seasons0 = var1_ext[int(t1*8):int(t1*8)+720] + var_seasons1 = np.reshape(var_seasons0,(90,8)) + var_seasons2 = MV2.average(var_seasons1,axis=1) #daily mean for 90 days + #print(var_seasons2.shape) + var_seasons[iyear,iseason,:] = var_seasons2 + var_seasons_f[iyear*90:iyear*90+90,iseason] = var_seasons2 + + return var_seasons_f + +def get_seasonal_data(var,seasons,years): + + '''Get seasonal data for each variable''' + nyears = len(years) + nseasons = len(seasons) + nsteps = int(nyears*90) + t0 = 0 + + var_seasons = MV2.zeros([nyears,nseasons,90])*np.nan #Daily mean for each season + var_seasons_f = MV2.zeros([nsteps,nseasons])*np.nan + for iyear in range(nyears): + if calendar.isleap(int(years[iyear]))==True: + nday = 366 + else: + nday = 365 + ntime = int(nday*24) + var1 = var[t0:t0+ntime] + var1_ext = np.concatenate((var1,var1),axis=0) + t0 = t0+ntime + + for iseason in range(nseasons): + if seasons[iseason]=='MAM': + if nday==366: t1 = 60 + else: t1 = 59 + if seasons[iseason]=='JJA': + if nday==366: t1 = 152 + else: t1 = 151 + if seasons[iseason]=='SON': + if nday==366: t1 = 244 + else: t1 = 243 + if seasons[iseason]=='DJF': + if nday==366: t1 = 335 + else: t1 = 334 + var_seasons0 = var1_ext[int(t1*24):int(t1*24)+2160] + var_seasons1 = np.reshape(var_seasons0,(90,24)) + var_seasons2 = MV2.average(var_seasons1,axis=1) #daily mean for 90 days + #print(var_seasons2.shape) + var_seasons[iyear,iseason,:] = var_seasons2 + var_seasons_f[iyear*90:iyear*90+90,iseason] = var_seasons2 + + return var_seasons_f + +def twolegged_metric_plot(parameter): + variables = parameter.variables + test_path = parameter.test_data_path + test_model = parameter.test_data_set + obs_path = parameter.obs_path + cmip_path = parameter.cmip_path + output_path = parameter.output_path + sites = parameter.sites + seasons = parameter.season + nseasons = len(seasons) + + if not os.path.exists(os.path.join(output_path,'figures',sites[0])): + os.makedirs(os.path.join(output_path,'figures',sites[0])) + #========================================================================== + # Calculate for observational data + #========================================================================== + print('ARM data',sites[0]) + obs_file = glob.glob(os.path.join(obs_path,sites[0][:3]+'armdiagsLAcoupling' + sites[0][3:5].upper()+'*c1.nc')) #read in data + print('Processing obs_file',obs_file) + fin = cdms2.open(obs_file[0]) + sh0 = fin('SH') + lh0 = fin('LH') + LCL0 = fin('LCL') + sm_ebbr0 = fin('soil_moisture_ebbr') + sm_swats0 = fin('soil_moisture_swats') + fin.close() + + #========================================================================== + # Calculate for model data + #========================================================================== + test_file = glob.glob(os.path.join(test_path,sites[0][:3]+'testmodel3hrLAcoupling' + sites[0][3:5].upper()+'*c1.nc')) #read in data + print('Processing test_file',test_file) + fin = cdms2.open(test_file[0]) + sh1 = fin('SH') + lh1 = fin('LH') + LCL1 = fin('LCL') + print('sh1: ',np.min(sh1),np.max(sh1)) + print('lh1: ',np.min(lh1),np.max(lh1)) + print('LCL1: ',np.min(LCL1),np.max(LCL1)) + fin.close() + + #================= + # Seasons: obs + #================= + years_obs = list(range(2004,2016)) + nday_obs = 90*len(years_obs) + sh = get_seasonal_data(sh0,seasons,years_obs) + lh = get_seasonal_data(lh0,seasons,years_obs) + LCL = get_seasonal_data(LCL0,seasons,years_obs) + sm_ebbr = get_seasonal_data(sm_ebbr0,seasons,years_obs) + sm_swats = get_seasonal_data(sm_swats0,seasons,years_obs) + + EF = MV2.zeros([nday_obs,nseasons])*np.nan + for im in range(nday_obs): + for iseason in range(nseasons): + EF[im,iseason] = lh[im,iseason]/(lh[im,iseason]+sh[im,iseason]) + + #================== + # Seasons: models + #================== + years_mod = list(range(2003,2015)) + nday_mod = 90*len(years_mod) + sh_mod = get_seasonal_data_3hr(sh1,seasons,years_mod) + lh_mod = get_seasonal_data_3hr(lh1,seasons,years_mod) + LCL_mod = get_seasonal_data_3hr(LCL1,seasons,years_mod) + + EF_mod = MV2.zeros([nday_mod,nseasons])*np.nan + for im in range(nday_mod): + for iseason in range(nseasons): + EF_mod[im,iseason] = lh_mod[im,iseason]/(lh_mod[im,iseason]+sh_mod[im,iseason]) + + #========================================================================== + # Calculate daily_mean values (10-day means) + #========================================================================== + nt_10day = int(nday_obs/10) + + sh_10day = MV2.zeros([nt_10day,nseasons])*np.nan + lh_10day = MV2.zeros([nt_10day,nseasons])*np.nan + LCL_10day = MV2.zeros([nt_10day,nseasons])*np.nan + EF_10day = MV2.zeros([nt_10day,nseasons])*np.nan + sm_ebbr_10day = MV2.zeros([nt_10day,nseasons])*np.nan + sm_swats_10day = MV2.zeros([nt_10day,nseasons])*np.nan + for im in range(nt_10day): + for iseason in range(nseasons): + tmp1 = sh[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + sh_10day[im,iseason] = tmp2 + + tmp1 = lh[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + lh_10day[im,iseason] = tmp2 + + tmp1 = LCL[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + LCL_10day[im,iseason] = tmp2 + + tmp1 = sm_ebbr[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + sm_ebbr_10day[im,iseason] = tmp2 + + tmp1 = sm_swats[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + sm_swats_10day[im,iseason] = tmp2 + + EF_10day[im,iseason] = lh_10day[im,iseason]/(lh_10day[im,iseason]+sh_10day[im,iseason]) + + #========================================================================== + # Calculate daily_mean values (10-day means) for models + #========================================================================== + nt_10day_mod = int(nday_mod/10) + + sh_10day_mod = MV2.zeros([nt_10day_mod,nseasons])*np.nan + lh_10day_mod = MV2.zeros([nt_10day_mod,nseasons])*np.nan + LCL_10day_mod = MV2.zeros([nt_10day_mod,nseasons])*np.nan + EF_10day_mod = MV2.zeros([nt_10day_mod,nseasons])*np.nan + for im in range(nt_10day_mod): + for iseason in range(nseasons): + tmp1 = sh_mod[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + sh_10day_mod[im,iseason] = tmp2 + + tmp1 = lh_mod[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + lh_10day_mod[im,iseason] = tmp2 + + tmp1 = LCL_mod[:,iseason] + tmp2 = np.mean(tmp1[10*im:10*im+10]) + LCL_10day_mod[im,iseason] = tmp2 + + EF_10day_mod[im,iseason] = lh_10day_mod[im,iseason]/(lh_10day_mod[im,iseason]+sh_10day_mod[im,iseason]) + + #================================================== + # Plots for observations + #================================================== + for iseason in range(nseasons): + #========================================================================== + # Plotting: Atmospheric coupling legs + # SH/LH/EF vs. LCL + #========================================================================== + + fig = plt.figure(figsize=[14,4], dpi=100) + gs = gridspec.GridSpec(ncols=3,nrows=1,figure=fig) + gs.update(wspace=0.25, hspace=0.15) + + ncols = 3 + nrows = 1 + for row in range(nrows): + for col in range(ncols): + tmp = ncols*row+col + ax = fig.add_subplot(gs[row,col]) + + data2 = LCL_10day[0:nt_10day,iseason]/1000. + + if col==0: + data1 = sh_10day[0:nt_10day,iseason] + str_xlabel = 'Sensible heat flux (W/m\u00b2)' + if seasons[iseason]=='DJF': xmax = 100 + if seasons[iseason]=='MAM': xmax = 150 + if seasons[iseason]=='JJA': xmax = 200 + if seasons[iseason]=='SON': xmax = 150 + plt.xlim([0,xmax]) + xx = xmax*0.6 + xseq = np.linspace(5,0.8*xmax, num=500) + if col==1: + data1 = lh_10day[0:nt_10day,iseason] + str_xlabel = 'Latent heat flux (W/m\u00b2)' + if seasons[iseason]=='DJF': xmax = 100 + if seasons[iseason]=='MAM': xmax = 150 + if seasons[iseason]=='JJA': xmax = 200 + if seasons[iseason]=='SON': xmax = 150 + plt.xlim([0,xmax]) + xx = xmax*0.6 + xseq = np.linspace(5,0.8*xmax, num=500) + if col==2: + data1 = EF_10day[0:nt_10day,iseason] + str_xlabel = 'Evaporative fraction' + plt.xlim([0,1]) + xx = 0.6 + xseq = np.linspace(0.15, 0.85, num=500) + + plt.scatter(data1, data2,s=30) + b, a = np.polyfit(data1, data2, deg=1) + r = scipy.stats.pearsonr(data1,data2) # Pearson's r + cc = '%.2f' % r[0] + ax.plot(xseq, a + b * xseq, color="k", lw=2.5) + plt.title('Obs. ('+seasons[iseason]+')',fontsize=14) + plt.xlabel(str_xlabel,fontsize=12) + plt.ylim([0,3.5]) + plt.ylabel('LCL (km)',fontsize=12) + plt.text(xx,2.8,"R = "+cc,fontsize=15) + + plt.savefig(output_path+'/figures/'+sites[0]+'/'+'Scatter_plot_'+seasons[iseason]+'_atmos_component_obs_'+sites[0]+'.png') + + #=========================================================== + # For models + #=========================================================== + + fig = plt.figure(figsize=[14,4], dpi=100) + gs = gridspec.GridSpec(ncols=3,nrows=1,figure=fig) + gs.update(wspace=0.25, hspace=0.15) + + ncols = 3 + nrows = 1 + for row in range(nrows): + for col in range(ncols): + tmp = ncols*row+col + ax = fig.add_subplot(gs[row,col]) + + data2 = LCL_10day_mod[0:nt_10day_mod,iseason]/1000. + + if col==0: + data1 = sh_10day_mod[0:nt_10day_mod,iseason] + str_xlabel = 'Sensible heat flux (W/m\u00b2)' + if seasons[iseason]=='DJF': xmax = 100 + if seasons[iseason]=='MAM': xmax = 150 + if seasons[iseason]=='JJA': xmax = 200 + if seasons[iseason]=='SON': xmax = 150 + plt.xlim([0,xmax]) + xx = xmax*0.6 + xseq = np.linspace(5,0.8*xmax, num=500) + if col==1: + data1 = lh_10day_mod[0:nt_10day_mod,iseason] + str_xlabel = 'Latent heat flux (W/m\u00b2)' + if seasons[iseason]=='DJF': xmax = 100 + if seasons[iseason]=='MAM': xmax = 150 + if seasons[iseason]=='JJA': xmax = 200 + if seasons[iseason]=='SON': xmax = 150 + plt.xlim([0,xmax]) + xx = xmax*0.6 + xseq = np.linspace(5,0.8*xmax, num=500) + if col==2: + data1 = EF_10day_mod[0:nt_10day_mod,iseason] + str_xlabel = 'Evaporative fraction' + plt.xlim([0,1]) + xx = 0.6 + xseq = np.linspace(0.15, 0.85, num=500) + + plt.scatter(data1, data2,s=30) + b, a = np.polyfit(data1, data2, deg=1) + r = scipy.stats.pearsonr(data1,data2) # Pearson's r + cc = '%.2f' % r[0] + #print(seasons[iseason],'r = ',cc) + #print('data1: ',data1) + #print('data2: ',data2) + ax.plot(xseq, a + b * xseq, color="k", lw=2.5) + plt.title('Mod. ('+seasons[iseason]+')',fontsize=14) + plt.xlabel(str_xlabel,fontsize=12) + plt.ylim([0,3.5]) + plt.ylabel('LCL (km)',fontsize=12) + plt.text(xx,2.8,"R = "+cc,fontsize=15) + + plt.savefig(output_path+'/figures/'+sites[0]+'/'+'Scatter_plot_'+seasons[iseason]+'_atmos_component_testmod_'+sites[0]+'.png') + + #========================================================================== + # Plotting: Terrestrial coupling legs + # soil moisture vs. SH/LH/EF + #========================================================================== + + fig = plt.figure(figsize=[14,4], dpi=100) + gs = gridspec.GridSpec(ncols=3,nrows=1,figure=fig) + gs.update(wspace=0.25, hspace=0.15) + + for row in range(nrows): + for col in range(ncols): + tmp = ncols*row+col + ax = fig.add_subplot(gs[row,col]) + + data1 = sm_swats_10day[0:nt_10day,iseason] + + if col==0: + data2 = sh_10day[0:nt_10day,iseason] + str_ylabel = 'Sensible heat flux (W/m\u00b2)' + if seasons[iseason]=='DJF': ymax = 100 + if seasons[iseason]=='MAM': ymax = 150 + if seasons[iseason]=='JJA': ymax = 200 + if seasons[iseason]=='SON': ymax = 150 + plt.ylim([0,ymax]) + yy = ymax*0.8 + xseq = np.linspace(0.22,0.35,num=500) + if col==1: + data2 = lh_10day[0:nt_10day,iseason] + str_ylabel = 'Latent heat flux (W/m\u00b2)' + if seasons[iseason]=='DJF': ymax = 100 + if seasons[iseason]=='MAM': ymax = 150 + if seasons[iseason]=='JJA': ymax = 200 + if seasons[iseason]=='SON': ymax = 150 + plt.ylim([0,ymax]) + yy = ymax*0.8 + xseq = np.linspace(0.22,0.35,num=500) + if col==2: + data2 = EF_10day[0:nt_10day,iseason] + str_ylabel = 'Evaporative fraction' + plt.ylim([0,1]) + yy = 0.098 + xseq = np.linspace(0.22,0.35,num=500) + + plt.scatter(data1, data2,s=30) + b, a = np.polyfit(data1, data2, deg=1) + r = scipy.stats.pearsonr(data1,data2) # Pearson's r + cc = '%.2f' % r[0] + ax.plot(xseq, a + b * xseq, color="k", lw=2.5) + plt.title('Obs. ('+seasons[iseason]+')',fontsize=14) + plt.ylabel(str_ylabel,fontsize=12) + plt.xlim([0.2,0.4]) + plt.xlabel('Soil moisture (m\u00b3/m\u00b3)',fontsize=12) + plt.text(0.32,yy,"R = "+cc,fontsize=15) + + plt.savefig(output_path+'/figures/'+sites[0]+'/'+'Scatter_plot_'+seasons[iseason]+'_land_component_obs_'+sites[0]+'.png') + #------------------------------------------------------------------------- +#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + + + diff --git a/arm_diags/src/utils.py b/arm_diags/src/utils.py index 7b8761d..25da401 100644 --- a/arm_diags/src/utils.py +++ b/arm_diags/src/utils.py @@ -9,13 +9,14 @@ # --------------------------------------------------------------------------------------- #=========================================================================================================================== - import numpy as np import numpy.ma as ma import cdms2 import cdutil import pdb from copy import deepcopy +import MV2 +import calendar def climo(var, season): """ @@ -59,8 +60,6 @@ def climo(var, season): # Compute time length dt = tbounds[:,1] - tbounds[:,0] - - # Convert to masked array v = var.asma() @@ -76,7 +75,7 @@ def climo(var, season): climo = ma.zeros([ncycle])#+list(np.shape(v))[1:]) for n in range(ncycle): idx = np.array( [ season_idx[cycle[n]][var_time_absolute[i].month-1] - for i in range(len(var_time_absolute)) ], dtype=np.int).nonzero() + for i in range(len(var_time_absolute)) ], dtype=int).nonzero() climo[n] = ma.average(v[idx], axis=0, weights=dt[idx]) # --------------------------------------------------------------------------------------- @@ -84,7 +83,6 @@ def climo(var, season): climo = climo.filled(np.nan) # --------------------------------------------------------------------------------------- - if var.id == 'tas': climo = climo - 273.15 @@ -93,3 +91,57 @@ def climo(var, season): return climo +#============================================================================================ +# Functions to get the diurnal cycle for particular seasons/years +# Output: var_seasons [nyears,nseasons,365,nhour] +#============================================================================================ + +def get_diurnal_cycle_seasons(var,seasons,years): + + '''Get seasonal data for each variable''' + nyears = len(years) + nseasons = len(seasons) + t0 = 0 + + time = var.getTime()[:] + if time[1]-time[0]==1: nhour=24 + if time[1]-time[0]==3: nhour=8 + #print('Time resolution: ', nhour) + + var_seasons = MV2.zeros([nyears,nseasons,365,nhour])*np.nan #diurnal cycle for each day + for iyear in range(nyears): + if calendar.isleap(int(years[iyear]))==True: + nday = 366 + else: + nday = 365 + ntime = int(nday*nhour) + var1 = var[t0:t0+ntime] + var1_ext = np.concatenate((var1,var1),axis=0) + t0 = t0+ntime + + for iseason in range(nseasons): + if seasons[iseason]=='ANN': + length = int(365*nhour) + var_seasons0 = var1[0:length] + var_seasons1 = np.reshape(var_seasons0,(365,nhour)) + var_seasons[iyear,iseason,:,:] = var_seasons1 + else: + if seasons[iseason]=='MAM': + if nday==366: t1 = 60 + else: t1 = 59 + if seasons[iseason]=='JJA': + if nday==366: t1 = 152 + else: t1 = 151 + if seasons[iseason]=='SON': + if nday==366: t1 = 244 + else: t1 = 243 + if seasons[iseason]=='DJF': + if nday==366: t1 = 335 + else: t1 = 334 + var_seasons0 = var1_ext[int(t1*nhour):int(t1*nhour)+90*nhour] + var_seasons1 = np.reshape(var_seasons0,(90,nhour)) + var_seasons[iyear,iseason,0:90,:] = var_seasons1 + + return var_seasons + + diff --git a/setup.py b/setup.py index 68ee11a..f10ba16 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,11 @@ from setuptools import find_packages,setup setup(name='arm_diags', - version='2.0', + version='4.0', description='An ARM data-oriented package for climate model evaluation', url='https://github.com/ARM-DOE/arm-gcm-diagnostics', - author='Jill Chengzhu Zhang, Cheng Tao, Shaocheng Xie and Zeshawn Shaheen', - author_email='zhang40@llnl.gov, tao4@llnl.gov and xie2@llnl.gov', + author='Cheng Tao, Jill Chengzhu Zhang, Shaocheng Xie and Zeshawn Shaheen', + author_email='tao4@llnl.gov, zhang40@llnl.gov, and xie2@llnl.gov', license='LLNL and ARM', packages=find_packages(exclude=["*.test", "*.test.*", "test.*", "test"]), zip_safe=False)

{}
'+varnames[j]+' (units: '+units[j]+')') + + for season in seasons: + two_figs_atm = 'diurnal_cycle_LAcoupling_'+season+'_'+variables[j]+'_'+title_name+'.html' + htmlfile_atm = open(output_path+'/html/'+two_figs_atm,"w") + fig1='../figures/{}/'.format(title_name)+'Diurnal_cycle_'+season+'_'+variables[j]+'_{}.png'.format(title_name) + + htmlfile_atm.write('
Line
') + htmlfile.write('
'+season+'') + htmlfile.write('