diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..44a043b3aa6964811a2d76e7d3ce982a0a98629f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.nc filter=lfs diff=lfs merge=lfs -text +*.mat filter=lfs diff=lfs merge=lfs -text diff --git a/RU/.gitattributes b/RU/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..9abd2058819fae6e5f68d95ef7ffd1a2abad7650 --- /dev/null +++ b/RU/.gitattributes @@ -0,0 +1 @@ +*.nc filter=lfs diff=lfs merge=lfs -text diff --git a/RU/Ep_approx.m b/RU/Ep_approx.m new file mode 100644 index 0000000000000000000000000000000000000000..c8d3d8bb74e19707e86f79eba313c8bfcf8aad2c --- /dev/null +++ b/RU/Ep_approx.m @@ -0,0 +1,52 @@ +function E_p = Ep_approx(prpt,alph,delta_ext,L_cbb,L_hbb,B_ssm,L,d_cbb,d_hbb) +% +% function E_p = Ep_approx(prpt,alph,delta_ext,L_cbb,L_hbb,B_ssm,L,d_cbb,d_hbb) +% +% The SSM and sensor act like a polarizer-analyzer pair. This function calculates +% the approximate radiance error generated by the polarizer-analyzer pair +% +% Inputs +% prpt: p_r * p_t for sensor + SSM (unitless) [nchan x 1] +% alph: analyzer angle alpha for sensor (radians) [scalar] +% delta_ext: polarizer angle for N scene views (radians) [1 x N] +% L_cbb: Radiance for cold cal reference (Rad units)) [nChan x N] +% L_hbb: Radiance for hot cal reference (Rad units)) [nChan x 1] +% B_ssm: Planck radiance for scene mirror temp (Rad units)) [nChan x 1] +% L: Scene radiance for N scene views (Rad units)) [nChan x 1] or [nChan x N] +% d_cbb: polarizer angle for CBB view (radians) [scalar] +% d_hbb: polarizer angle for HBB view (radians) [scalar] +% +% Outputs +% E_p calibration bias due to polarization (Rad units) [nChan x N] +% +% 2020-08-19 JKT +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) + +if size(L,2) == 1 + L = repmat(L,1,length(delta_ext)); +elseif size(L,2) ~= length(delta_ext) + fprintf(1, 'Ep_approx: ERROR Invalid scene radiance dimensions\n'); +end +if abs(d_cbb) > 2*pi + fprintf(1, 'Ep_approx: ERROR delta CBB out of range, should be in units of radians\n') + return +end +if abs(d_hbb) > 2*pi + fprintf('Ep_approx: ERROR delta HBB out of range, should be in units of radians\n') + return +end +E_p = NaN*ones(length(L_cbb),length(delta_ext)); % N_{d.wn} x N_{d.delta_ext} + +for ii = 1:length(delta_ext) + d_ext = delta_ext(ii); + L_ext = L(:,ii); + % approximate equation + term1 = prpt.*(L_ext*cos(2*(d_ext - alph))); + term2 = -prpt.*(L_hbb.*((L_ext - L_cbb)./(L_hbb - L_cbb))*cos(2*(d_hbb - alph))); + term3 = -prpt.*(L_cbb.*((L_hbb - L_ext)./(L_hbb - L_cbb))*cos(2*(d_cbb - alph))); + term4 = -B_ssm.*prpt.*(cos(2*(d_ext - alph))); + term5 = +B_ssm.*prpt.*(((L_ext - L_cbb)./(L_hbb - L_cbb))*cos(2*(d_hbb - alph))); + term6 = +B_ssm.*prpt.*(((L_hbb - L_ext)./(L_hbb - L_cbb))*cos(2*(d_cbb - alph))); + E_p(:,ii) = term1 + term2 + term3 + term4 + term5 + term6; +end +return diff --git a/RU/ICTradModelRU_L1b_aux.m b/RU/ICTradModelRU_L1b_aux.m new file mode 100644 index 0000000000000000000000000000000000000000..9cec1a966b0dcd3c01d5423b1aade72cbffa77cb --- /dev/null +++ b/RU/ICTradModelRU_L1b_aux.m @@ -0,0 +1,262 @@ +function B = ICTradModelRU_L1b_aux(sensor,T_ICT,T_CRIS,ICT_Param,ru_term,ru_value) +% +% function B = ICTradModelRU_L1b_aux(sensor,T_ICT,T_CRIS,ICT_Param,ru_term,ru_value) +% +% Compute ICT predicted radiance using ICT radiometric model prescribed by ATBD +% with perturbation to a single term +% +% Inputs +% sensor sparse spectral params structure +% .band +% .v +% .output_range +% T_ICT ICT Temperature +% T_CRIS CrIS temperature struct +% ICT_Param ICT radiometric model parameters +% ru_term string indicating ru_term to perturb +% ru_value size of perturbation +% +% Outputs +% B Structure of predicted ICT radiance variables +% .emitted emitted radiance +% .wn wavenumber scale +% .SSM_Baffle SSM Baffle term reflected radiance +% .ICT_baffle ICT baffle term reflected radiance +% .OMA OMA term reflected radiance +% .BS_warm BS_warm term reflected radiance +% .BS_cold BS_cold term reflected radiance +% .Space Earth/Space term reflected radiance +% .reflected total reflected radiance +% .total total radiance (emitted and reflected) +% .V view factors (struct) +% .e emissivities (struct) +% .r reflectivies (.SSM) +% .T temperatures (struct) +% .e_ICT ICT emissivity +% .T_ICT ICT temperature +% .ru_term RU term to perturb +% .ru_value value of perturbation +% .no_perturb_val +% .perturbed_val +% +% 2020-08-19 JKT +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) + +wn = sensor.v_onaxis; + +ICT_wnum = ICT_Param.(sprintf('%s_ICT_wnum',lower(sensor.band))); +ICT_emiss = ICT_Param.(sprintf('%s_ICT_emiss',lower(sensor.band))); +ICT_Baffle_emiss = ICT_Param.(sprintf('%s_ICT_Baffle_emiss',lower(sensor.band))); +Housing_emiss = ICT_Param.(sprintf('%s_Housing_emiss',lower(sensor.band))); +ScanBaffle_emiss = ICT_Param.(sprintf('%s_ScanBaffle_emiss',lower(sensor.band))); +ScanMirror_emiss = ICT_Param.(sprintf('%s_ScanMirror_emiss',lower(sensor.band))); +Earth_emiss = ICT_Param.(sprintf('%s_Earth_emiss',lower(sensor.band))); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% ICT emissivity interpolation to wavenumber grid +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Interpolate 4-min-EP emissivity to the on-axis sensor grid. +%% The wavenumber values corresponding to the emissivity values in the engineering packet are on the normal spectral resolution and on user grid +e_ICT = interp1(ICT_wnum,ICT_emiss,wn,'nearest','extrap'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Temperature, emissivity and view factor init +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% SSM +%%---------- +%r.SSM = 1-ICT_Param.Band(iband).Emissivity.ScanMirrorPts; +r.SSM = 1-ScanMirror_emiss; + +%% SSM_Baffle +%%---------- +%e.SSM_Baffle = ICT_Param.Band(iband).Emissivity.ScanBafflePts; +e.SSM_Baffle = ScanBaffle_emiss; +T.SSM_Baffle = T_CRIS.ssm_baffle_temp + T_CRIS.ssm_baffle_corr_temp; +T.SSM_Baffle(isnan(T.SSM_Baffle)) = 0; +V.SSM_Baffle = ICT_Param.View_Factor.ScanBaffle; + +%% ICT_baffle +%%---------- +%e.ICT_baffle = ICT_Param.Band(iband).Emissivity.ICT_BafflePts; +e.ICT_baffle = ICT_Baffle_emiss; +T.ICT_baffle = T_ICT; +V.ICT_baffle = ICT_Param.View_Factor.ICTBaffle; + +%% OMA + Frame + Other +%%---------- +%e.OMA = ICT_Param.Band(iband).Emissivity.HousingPts; +e.OMA = Housing_emiss; +T.OMA = mean(0.5*T_CRIS.oma_struct_temp_1 + 0.5*T_CRIS.oma_struct_temp_2); +V.OMA = ICT_Param.View_Factor.OMAandFrame; + +%% BS_warm +%%---------- +e.BS_warm = e.OMA; +T.BS_warm = T.OMA; +V.BS_warm = ICT_Param.View_Factor.BeamSplitterWarm; + +%% BS_cold +%%---------- +T.BS_cold = T_ICT; +V.BS_cold = ICT_Param.View_Factor.BeamSplitterCold; + +%% Space/Earth Reflected +%%---------- +e.Space = Earth_emiss; +T.Space = ICT_Param.Earth_Temperature; +V.Space = ICT_Param.View_Factor.Space; + +no_perturb_val = []; % initialize, will remain at this value for no perturbation +perturbed_val = []; % initialize, will remain at this value for no perturbation + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Perturbation +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch ru_term + case 'e_ICT' + no_perturb_val = e_ICT; + e_ICT = e_ICT*(1-ru_value); + e_ICT(e_ICT > 1) = 1; + e_ICT(e_ICT < 0) = 0; + perturbed_val = e_ICT; + + case 'T_ICT' + no_perturb_val = T_ICT; + T_ICT = T_ICT + ru_value; + perturbed_val = T_ICT; + + case 'SSM_scan_mirror_baffle' + no_perturb_val = T.SSM_Baffle; + T.SSM_Baffle = T.SSM_Baffle + ru_value; + perturbed_val = T.SSM_Baffle; + + case 'T_ScanBaffleCorrection' + no_perturb_val = T.SSM_Baffle; + T.SSM_Baffle = T.SSM_Baffle + ru_value; + perturbed_val = T.SSM_Baffle; + + case 'T_ICT_baffle' + no_perturb_val = T.ICT_baffle; + T.ICT_baffle = T.ICT_baffle + ru_value; + perturbed_val = T.ICT_baffle; + + case 'T_OMA' % OMA + Frame + Other + no_perturb_val = T.OMA; + T.OMA = T.OMA + ru_value; + perturbed_val = T.OMA; + + case 'T_Frame' % no longer used + no_perturb_val = T.Frame; + T.Frame = T.Frame + ru_value; + perturbed_val = T.Frame; + + case 'T_BS_warm' + no_perturb_val = T.BS_warm; + T.BS_warm = T.BS_warm + ru_value; + perturbed_val = T.BS_warm; + + case 'T_BS_cold' + no_perturb_val = T.BS_cold; + T.BS_cold = T.BS_cold + ru_value; + perturbed_val = T.BS_cold; + + case 'T_Space' + no_perturb_val = T.Space; + T.Space = T.Space + ru_value; + perturbed_val = T.Space; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% ICT emission +% (ref: eq 75 in 474-00032, Rev C) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +B.emitted = e_ICT .* bt2rad(wn,T_ICT); +B.wn = wn; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Reflected term 1: SSM Baffle +% (ref: eq 76 in 474-00032, Rev C) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if V.SSM_Baffle == 0 + B.SSM_Baffle = zeros(size(B.wn)); +else + B.SSM_Baffle = (1 - e_ICT) .* e.SSM_Baffle * V.SSM_Baffle .* bt2rad(wn,T.SSM_Baffle); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Reflected term 2: ICT Baffle +% (ref: eq 78a in 474-00032, Rev C) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if V.ICT_baffle == 0 + B.ICT_baffle = zeros(size(B.wn)); +else + B.ICT_baffle = (1 - e_ICT) .* e.ICT_baffle * V.ICT_baffle .* bt2rad(wn,T.ICT_baffle); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Reflected term 3a,b,c: OMA, frame, other, Beamsplitter Warm +% (ref: eq 77 in 474-00032, Rev C) +% V = 0.214 for OMA, Other, Frame terms in ATBD (= 0.0590 + 0.0100 + 0.1450) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% OMA +%%---------- +if V.OMA == 0 + B.OMA = zeros(size(B.wn)); +else + B.OMA = (1 - e_ICT) .* e.OMA * r.SSM * V.OMA .* bt2rad(wn,T.OMA); +end + +%% BS_Warm +%%---------- +if V.BS_warm == 0 + B.BS_warm = zeros(size(B.wn));; +else + B.BS_warm = (1 - e_ICT) .* e.BS_warm * r.SSM * V.BS_warm .* bt2rad(wn,T.BS_warm); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Reflected term 4: Beamsplitter Cold +% (ref: eq 78b in 474-00032, Rev C) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if V.BS_cold == 1 + B.BS_cold = (1 - e_ICT) .* r.SSM^2 .* 0.5 * V.BS_cold .* bt2rad(wn,T.BS_cold); % Consistent with ATBD +else + B.BS_cold = (1 - e_ICT) .* r.SSM^2 .* 0.5 * V.BS_cold .* bt2rad(wn,T.BS_cold); % SNPP +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Reflected term 5: Space/Earth View +% (ref: eq 78c in 474-00032, Rev C) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if V.Space == 0 + B.Space = zeros(size(B.wn));; +else + B.Space = (1 - e_ICT) .* V.Space .* e.Space .* bt2rad(wn,T.Space); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% total reflected radiance into ICT cavity +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +V.Total = V.SSM_Baffle + V.ICT_baffle + V.OMA + V.BS_warm + V.BS_cold + V.Space; % should total 1, for check only +B.reflected = B.SSM_Baffle + B.ICT_baffle + B.OMA + B.BS_warm + B.BS_cold + B.Space; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Total radiance from ICT +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +B.total = B.emitted + B.reflected; + +B.wn = wn; +B.V = V; +B.e = e; +B.r = r; +B.T = T; +B.e_ICT = e_ICT; +B.T_ICT = T_ICT; +B.ru_term = ru_term; +B.ru_value = ru_value; +B.no_perturb_val = no_perturb_val; +B.perturbed_val = perturbed_val; + +return diff --git a/RU/J1_L1B_ru_tool_param_file.nc b/RU/J1_L1B_ru_tool_param_file.nc new file mode 100644 index 0000000000000000000000000000000000000000..f98e4e87cea5f2d2071d47dc942cc3ad92165dab --- /dev/null +++ b/RU/J1_L1B_ru_tool_param_file.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c80a8d82ae12d8061fed579c187def89e13b80aa43bce271ea6f261a1ba5528 +size 198316 diff --git a/RU/SNPP_L1B_ru_tool_param_file.nc b/RU/SNPP_L1B_ru_tool_param_file.nc new file mode 100644 index 0000000000000000000000000000000000000000..e284e0cf6c70e9919fcdcb0e38ab53efe105bc4e --- /dev/null +++ b/RU/SNPP_L1B_ru_tool_param_file.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a9389260928e98dccc68206c87bde00e12b2db4d1118088ce35084901460884 +size 198316 diff --git a/RU/TEST_INPUT/SNDR.J1.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201204050506.nc b/RU/TEST_INPUT/SNDR.J1.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201204050506.nc new file mode 100644 index 0000000000000000000000000000000000000000..9d85e52448d8c51d25e7ee0b8aa03da6cb54fae4 --- /dev/null +++ b/RU/TEST_INPUT/SNDR.J1.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201204050506.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f008b1e83c3574fe879c5a7bd6d1d7f15c2f05c131a164d00136a7f87434cfa8 +size 175523775 diff --git a/RU/TEST_INPUT/SNDR.SNPP.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201219125854.nc b/RU/TEST_INPUT/SNDR.SNPP.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201219125854.nc new file mode 100644 index 0000000000000000000000000000000000000000..10e7804c1520a381e435f97f5a1b855b43faff11 --- /dev/null +++ b/RU/TEST_INPUT/SNDR.SNPP.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201219125854.nc @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa6c558c697c15cb52d8bb28305d4c9588b6c26f4d5dc2a40364655391214441 +size 176201220 diff --git a/RU/bt2rad.m b/RU/bt2rad.m new file mode 100644 index 0000000000000000000000000000000000000000..6cba838fae5b3e93754ca4bf268b60c8a4766682 --- /dev/null +++ b/RU/bt2rad.m @@ -0,0 +1,53 @@ +function radiance = bt2rad(freq,bt); +% +% function radiance = bt2rad(freq,bt); +% +% compute radiance given wavenumbers and brightness temperature. +% +% Inputs: +% freq wavenumbers (Nx1) in 1/cm +% bt brightnes temperature (Nx1) in Kelvin +% Outputs: +% radiance Planck radiances (Nx1) in mW/(m^2 sr. 1/cm) +% +% see also RADTOT.M, RAD2BT.M, TTORAD.M +% +% DCT 11/11-99 +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) +% + +% fundamental constants: +% (Cohen, E.R. and B.N. Taylor, The 1986 CODATA recommended values +% of the fundamental physical constants, Journal of Research of +% the National Bureau of Standard, 92(2), March-April 1987.) + +h = 6.6260755E-34; % Planck constant in Js +c = 2.99792458E8; % photon speed in m/s +k = 1.380658E-23; % Boltzmann constant in J/K + +c1 = 2*h*c*c*1e8; +c2 = h*c/k*1e2; + +radiance = 1e3 * c1.*(freq.*freq.*freq)./(exp((c2.*freq)./bt)-1); + +ind = find(bt < 0); +if length(ind) ~= 0 + radiance = nan*real(radiance); + disp('WARNING: negative inputs to BT2RAD') +end +ind = find(~isreal(bt)); +if length(ind) ~= 0 + radiance = nan*real(radiance); + disp('WARNING: imaginary inputs to BT2RAD') +end +ind = find(isnan(bt)); +if length(ind) ~= 0 + radiance = nan*real(radiance); + disp('WARNING: NaN inputs to BT2RAD') +end +ind = find(isinf(bt)); +if length(ind) ~= 0 + radiance = nan*real(radiance); + disp('WARNING: Inf inputs to BT2RAD') +end +return diff --git a/RU/convert_anc_to_structs.m b/RU/convert_anc_to_structs.m new file mode 100644 index 0000000000000000000000000000000000000000..b91bce391c7c51030c490570b79d8d582d913caf --- /dev/null +++ b/RU/convert_anc_to_structs.m @@ -0,0 +1,83 @@ +function [ICT_Param,RU,nonlin,polcorr_param] = convert_anc_to_structs(nc_struct); +% +% function [ICT_Param,RU,nonlin,polcorr_param] = convert_anc_to_structs(nc_struct); +% +% This function converts the contents from the CrIS L1b RU ancillary file +% to ICT_Param, RU, nonlin, and polcorr structures for use in the RU calculations +% +% Input +% nc_struct structure of vars read from CrIS L1b RU ancillary file +% +% Output +% ICT_Param ICT ancillary parameters [struct] +% RU Radiometric Uncertainty ancillary parameters [struct] +% nonlin nonlinearity corretion ancillary parameters [struct] +% polcorr_param polarization correction ancillary parameters [struct] +% +% JKT 2021-Aug-26 +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ICT_Param.Earth_Temperature = nc_struct.ICT_Param_Earth_Temperature; +ICT_Param.lw_ICT_wnum = nc_struct.wnum_lw; +ICT_Param.lw_ICT_emiss = nc_struct.ICT_Param_lw_ICT_emiss; +ICT_Param.lw_ICT_Baffle_emiss = nc_struct.ICT_Param_lw_ICT_Baffle_emiss; +ICT_Param.lw_Housing_emiss = nc_struct.ICT_Param_lw_Housing_emiss; +ICT_Param.lw_ScanBaffle_emiss = nc_struct.ICT_Param_lw_ScanBaffle_emiss; +ICT_Param.lw_ScanMirror_emiss = nc_struct.ICT_Param_lw_ScanMirror_emiss; +ICT_Param.lw_Earth_emiss = nc_struct.ICT_Param_lw_Earth_emiss; +ICT_Param.mw_ICT_wnum = nc_struct.wnum_mw; +ICT_Param.mw_ICT_emiss = nc_struct.ICT_Param_mw_ICT_emiss; +ICT_Param.mw_ICT_Baffle_emiss = nc_struct.ICT_Param_mw_ICT_Baffle_emiss; +ICT_Param.mw_Housing_emiss = nc_struct.ICT_Param_mw_Housing_emiss; +ICT_Param.mw_ScanBaffle_emiss = nc_struct.ICT_Param_mw_ScanBaffle_emiss; +ICT_Param.mw_ScanMirror_emiss = nc_struct.ICT_Param_mw_ScanMirror_emiss; +ICT_Param.mw_Earth_emiss = nc_struct.ICT_Param_mw_Earth_emiss; +ICT_Param.sw_ICT_wnum = nc_struct.wnum_sw; +ICT_Param.sw_ICT_emiss = nc_struct.ICT_Param_sw_ICT_emiss; +ICT_Param.sw_ICT_Baffle_emiss = nc_struct.ICT_Param_sw_ICT_Baffle_emiss; +ICT_Param.sw_Housing_emiss = nc_struct.ICT_Param_sw_Housing_emiss; +ICT_Param.sw_ScanBaffle_emiss = nc_struct.ICT_Param_sw_ScanBaffle_emiss; +ICT_Param.sw_ScanMirror_emiss = nc_struct.ICT_Param_sw_ScanMirror_emiss; +ICT_Param.sw_Earth_emiss = nc_struct.ICT_Param_sw_Earth_emiss; + +ICT_Param.View_Factor.Space = nc_struct.ICT_Param_A_Space; +ICT_Param.View_Factor.BeamSplitterCold = nc_struct.ICT_Param_A_BeamSplitterCold; +ICT_Param.View_Factor.BeamSplitterWarm = nc_struct.ICT_Param_A_BeamSplitterWarm; +ICT_Param.View_Factor.OMAandFrame = nc_struct.ICT_Param_A_OMAandFrame; +ICT_Param.View_Factor.ICTBaffle = nc_struct.ICT_Param_A_ICTBaffle; +ICT_Param.View_Factor.ScanBaffle = nc_struct.ICT_Param_A_ScanBaffle; + +RU.dT_ict = nc_struct.RU_dT_ict; +RU.de_ict = nc_struct.RU_de_ict; +RU.dT_ict_ref_meas = nc_struct.RU_dT_ict_ref_meas; +RU.dT_ict_ref_model = nc_struct.RU_dT_ict_ref_model; +RU.dprpt = nc_struct.RU_dprpt; +RU.dalpha = nc_struct.RU_dalpha; +RU.lw_da2 = nc_struct.RU_lw_da2; +RU.mw_da2 = nc_struct.RU_mw_da2; +RU.sw_da2 = nc_struct.RU_sw_da2; + +nonlin.lw_a2 = nc_struct.nonlin_lw_a2; +nonlin.mw_a2 = nc_struct.nonlin_mw_a2; +nonlin.sw_a2 = nc_struct.nonlin_sw_a2; + +polcorr_param.delta_SSM = nc_struct.polcorr_delta_SSM; + +polcorr_param.lw_wn = repmat(nc_struct.wnum_lw(:),1,9); +polcorr_param.lw_prpt = nc_struct.polcorr_lw_prpt; +polcorr_param.lw_alph = nc_struct.polcorr_lw_alph; +polcorr_param.lw_delta_cbb = nc_struct.polcorr_delta_cbb; +polcorr_param.lw_delta_hbb = nc_struct.polcorr_delta_hbb; +polcorr_param.mw_wn = repmat(nc_struct.wnum_mw(:),1,9); +polcorr_param.mw_prpt = nc_struct.polcorr_mw_prpt; +polcorr_param.mw_alph = nc_struct.polcorr_mw_alph; +polcorr_param.mw_delta_cbb = nc_struct.polcorr_delta_cbb; +polcorr_param.mw_delta_hbb = nc_struct.polcorr_delta_hbb; +polcorr_param.sw_wn = repmat(nc_struct.wnum_sw,1,9); +polcorr_param.sw_prpt = nc_struct.polcorr_sw_prpt; +polcorr_param.sw_alph = nc_struct.polcorr_sw_alph; +polcorr_param.sw_delta_cbb = nc_struct.polcorr_delta_cbb; +polcorr_param.sw_delta_hbb = nc_struct.polcorr_delta_hbb; + +return diff --git a/RU/cris_calbudget_1gran_nc_wrapper.m b/RU/cris_calbudget_1gran_nc_wrapper.m new file mode 100644 index 0000000000000000000000000000000000000000..363e2da7d2c57c5a2714c9973726b5a712b3e564 --- /dev/null +++ b/RU/cris_calbudget_1gran_nc_wrapper.m @@ -0,0 +1,60 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This is a wrapper script for testing the generation of the CrIS NASA L1b for a single L1b granule +% and utilizes the netcdf4 formatted parameter files +% The user must set the following (within USER INPUT section of script) +% +% sat_name satellite name ('J1' or 'SNPP') +% l1b_fname L1b granule name (including path if not in same directory as code) +% saveTotalRU_FLAG set to 1 if you want to save the RSS RU to a mat file +% +% The primary contributors to the CrIS radiometric uncertainty are +% ICT temperature uncertainty +% ICT emissivity uncertainty +% uncertainty in the the other temperatures in the ICT radiometric model (modeled and measured) +% uncertainty in the quadratic coefficient NLC coefficient (a2) +% polarization correction uncertainty +% (sensor polarization angle alpha, and combined SSM and sensor polarization prpt) +% +% RU term 1: e_ict ICT rad model, emitted radiance +% RU term 2: T_ict ICT rad model, emitted radiance +% RU term 3: T_SSM_scan_mirror_baffle ICT rad model, reflected radiance (measured T) +% RU term 4: T_ScanBaffleCorrection ICT rad model, reflected radiance (modeled T) +% RU term 5: T_ICT_baffle ICT rad model, reflected radiance (measured T) +% RU term 6a: T_OMA, T_Frame ICT rad model, reflected radiance (measured T) +% RU term 6b: T_BS_warm ICT rad model, reflected radiance (measured T) +% RU term 7: T_BS_cold ICT rad model, reflected radiance (measured T) +% RU term 8: T_Space ICT rad model, reflected radiance (modeled T) +% RU term 9: prpt polarization correction +% RU term 10: alpha polarization correction +% RU term 11: a2 nonlinearity correction +% +% Refer to the NASA CrIS L1b RU document and ATBD for details on the ICT radiometric model +% Each reflected term in the ICT radiometric model also has a view factor and emissivity, but the uncertainty +% in those quantities produce negligible contributions to the CrIS radiometric uncertainty and are not perturbed for the RU estimate +% J1 has an improved ICT emissivity, and the view factors of some of the reflected terms are set to zero as a result +% +% JKT 2020-Sep-13 +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% START: USER INPUT +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +sat_name = 'SNPP'; % set to 'J1' or 'SNPP' +l1b_fname = 'SNDR.SNPP.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201219125854.nc'; % set to file name of v3 L1b granule +%sat_name = 'J1'; % set to 'J1' or 'SNPP' +%l1b_fname = 'SNDR.J1.CRIS.20191031T0012.m06.g003.L1B.std.v03_08.G.201204050506.nc'; % set to file name of v3 L1b granule +l1b_pname = '/Users/joet/git/cris_l1b_user/RU/TEST_INPUT'; % set to path to v3 L1b granule +ru_code_pname = pwd; % set to path of the RU code + +saveTotalRU_FLAG = 1; % set to 1 if you want to save the RSS RU to a mat file +pname_out = fullfile(pwd,'RU_OUT_NC'); % set to path for RU output files +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% END: USER INPUT +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +mkdir(pname_out) +addpath(ru_code_pname); + +RU = cris_gran_RU_ncparam(sat_name,fullfile(l1b_pname,l1b_fname),saveTotalRU_FLAG,pname_out); diff --git a/RU/cris_gran_RU_ncparam.m b/RU/cris_gran_RU_ncparam.m new file mode 100644 index 0000000000000000000000000000000000000000..a6e9c490f6390f50a9a4c8bf553c57198bfe8382 --- /dev/null +++ b/RU/cris_gran_RU_ncparam.m @@ -0,0 +1,284 @@ +function RU = cris_gran_RU_ncparam(sat_name,l1b_fname,saveTotalRU_FLAG,pname_out); +% +% function RU = cris_gran_RU_ncparam(sat_name,l1b_fname,saveTotalRU_FLAG,pname_out); +% +% This is a function for generation of the CrIS NASA L1b for a single L1b granule +% and utilizes the netcdf4 formatted parameter files +% +% Inputs +% sat_name satellite name ('J1' or 'SNPP') +% l1b_fname L1b granule name (including path if not in same directory as code) +% saveTotalRU_FLAG set to 1 if you want to save the RSS RU to a mat file +% pname_out output directory +% +% JKT 2021-Aug-26 +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% code will loop over bands +bands{1} = 'lw'; +bands{2} = 'mw'; +bands{3} = 'sw'; + +%%============================================================ +%% RU STEP 1a: Load ancillary data from static file (satellite dependent) +%%============================================================ +switch sat_name + case 'J1' + % J1 + jnk = rd_nc4('J1_L1B_ru_tool_param_file.nc'); + case 'SNPP' + % SNPP + jnk = rd_nc4('SNPP_L1B_ru_tool_param_file.nc'); +end +%%============================================================ +%% RU STEP 1b: separate .nc param file contents into ICT_Param, RU, +%% nonlin, polcorr_param structures used in this code package +%%============================================================ +[ICT_Param,RU,nonlin,polcorr_param] = convert_anc_to_structs(jnk); + +%%============================================================ +%% RU STEP 1c: copy data from anc file to expected var names for this code package +%%============================================================ +dT_ict = RU.dT_ict; +de_ict = RU.de_ict; +dT_ict_ref_meas = RU.dT_ict_ref_meas; +dT_ict_ref_model = RU.dT_ict_ref_model; +dprpt = RU.dprpt; +dalpha = RU.dalpha; +da2.lw = RU.lw_da2; +da2.mw = RU.mw_da2; +da2.sw = RU.sw_da2; + +sensor_all.lw.a2_now = nonlin.lw_a2; +sensor_all.mw.a2_now = nonlin.mw_a2; +sensor_all.sw.a2_now = nonlin.sw_a2; + +%%%%%%%%%% +%% create an opts structure +%% not needed to calc RU estimate, but used here to record configuration options +%%%%%%%%%% +opts.extraFLAG = 1; +opts.l1b_fname = l1b_fname; +opts.bands = bands; +opts.sat_name = sat_name; + +%%%%%%%%%% +% create output file name +% not required to calc RU estimate, but used here for optional output +%%%%%%%%%% +[~,fname_out,~] = fileparts(l1b_fname); +fname_out = sprintf('%s_RU',fname_out); + +%%============================================================ +%% RU STEP 2: Load v3 L1b data +%%============================================================ +l1b_dat = read_l1b_for_RU(l1b_fname); + +%%%%%%%%%% +%% save opts params +%% not needed to calc RU estimate, but used here to record configuration options +%%%%%%%%%% +opts.neonl = l1b_dat.aux.neon_wlen; +save(fullfile(pname_out,sprintf('%sopts.mat',fname_out)), 'opts'); + +%%%%%%%%%% +% store lat and lon data to RU structure +% not required to calc RU estimate, but are useful for plotting and statistical analysis +%%%%%%%%%% +%RU.lat = l1b_dat.lat; +%RU.lon = l1b_dat.lon; + +%%%%%%%%%% +%% sparsely populated sensor and user structs are used by this code package +%%%%%%%%%% +user_all.lw.band = 'LW'; +user_all.lw.v = l1b_dat.wnum_lw; +user_all.lw.output_range = [user_all.lw.v(1) user_all.lw.v(end)]; + +user_all.mw.band = 'MW'; +user_all.mw.v = l1b_dat.wnum_mw; +user_all.mw.output_range = [user_all.mw.v(1) user_all.mw.v(end)]; + +user_all.sw.band = 'SW'; +user_all.sw.v = l1b_dat.wnum_sw; +user_all.sw.output_range = [user_all.sw.v(1) user_all.sw.v(end)]; + +sensor_all.lw.band = 'LW'; +sensor_all.mw.band = 'MW'; +sensor_all.sw.band = 'SW'; + +% generate RU, loop over detector bands +%%%%%%%%%%%%%%%%%%%% +for jj = 1:length(bands) + + clear rad1 rad2 user sensor scTime sci eng geo ru_rad + user = user_all.(lower(bands{jj})); + sensor = sensor_all.(lower(bands{jj})); + + v = l1b_dat.(sprintf('wnum_%s',bands{jj})); + + %%============================================================ + %% RU STEP 3: Remove polarization correction from L1b v3 radiance + %%============================================================ + % rad_nopolcorr = radiance without nominal polarization correction + % rad_polcorr = radiance with nominal polarization correction + rad_polcorr = l1b_dat.(sprintf('rad_%s',bands{jj})); + [rad_nopolcorr,pol_params_nopolcorr] = pol_correctionRU_L1bonly(v, l1b_dat, sensor, user, ... + ICT_Param, polcorr_param, sat_name, 'prpt', -2); % prpt = prpt * (1+ru_value) + + %% for RU calcs, rad1 should be the radiance prior to polarization correction + rad1 = rad_nopolcorr; + l1b_dat.(sprintf('rad_%s',bands{jj})) = rad1; + l1b_dat.(sprintf('rad_%s_pc',bands{jj})) = rad_polcorr; + + %%============================================================ + %% RU STEP 4: Assess ICT radiometric model uncertainties (RU terms 1, 2, 3, 4, 5, 6a/b, 7, 8) + %%============================================================ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % temperature and emissivity perturbations via cris_l1b_recal + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % RU term 1: e_ict + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, 'e_ICT', de_ict); + ru_rad.de_ict = rad2 - rad1; + ru_delta.de_ict = de_ict; + + % RU term 2: T_ict + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, 'T_ICT', dT_ict); + ru_rad.dT_ict = rad2 - rad1; + ru_delta.dT_ict = dT_ict; + + % RU term 3: SSM_scan_mirror_baffle + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'SSM_scan_mirror_baffle', dT_ict_ref_meas); + ru_rad.dT_SSM_scan_mirror_baffle = rad2 - rad1; + ru_delta.dT_SSM_scan_mirror_baffle = dT_ict_ref_meas; + + % RU term 4: T_ScanBaffleCorrection + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'T_ScanBaffleCorrection', dT_ict_ref_model); + ru_rad.dT_ScanBaffleCorrection = rad2 - rad1; + ru_delta.dT_ScanBaffleCorrection = dT_ict_ref_model; + + % RU term 5: T_ICT_baffle + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'T_ICT_baffle', dT_ict_ref_meas); + ru_rad.dT_ICT_baffle = rad2 - rad1; + ru_delta.dT_ICT_baffle = dT_ict_ref_meas; + + % RU term 6a: T_OMA, T_Frame + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'T_OMA', dT_ict_ref_meas); + ru_rad.dT_OMA = rad2 - rad1; + ru_delta.dT_OMA = dT_ict_ref_meas; + + % RU term 6b: T_BS_warm %% We could potentially combine term 6a and 6b + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'T_BS_warm', dT_ict_ref_meas); + ru_rad.dT_BS_warm = rad2 - rad1; + ru_delta.dT_BS_warm = dT_ict_ref_meas; + + % RU term 7: T_BS_cold + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'T_BS_cold', dT_ict_ref_meas); + ru_rad.dT_BS_cold = rad2 - rad1; + ru_delta.dT_BS_cold = dT_ict_ref_meas; + + % RU term 8: T_Space (Earth / Space reflected out.eng.ICT_Param.Earth_Temperature) + %%%%%%%%%%%%%%%%%%%% + [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, lower(bands{jj}), ICT_Param, ... + 'T_Space', dT_ict_ref_model); + ru_rad.dT_Earth = rad2 - rad1; + ru_delta.dT_Earth = dT_ict_ref_model; + + %%============================================================ + %% RU STEP 5: Assess RU associated with polarization correction (RU terms 9, 10) + %%============================================================ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % RU associated with polarization correction + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % RU term 9: polarization correction, prpt + %%%%%%%%%%%%%%%%%%%% + %% apply polarization correction with perturbed prpt + [rad3,pol_params_prpt_pert] = pol_correctionRU_L1bonly(v, l1b_dat, sensor, user, ICT_Param, ... + polcorr_param, sat_name, 'prpt', dprpt); + ru_rad.dprpt = rad_polcorr - rad3; + ru_delta.dprpt = dprpt; + + % RU term 10: polarization correction, alpha + %%%%%%%%%%%%%%%%%%%% + %% apply polarization correction with perturbed alpha + [rad3,pol_params_prpt_pert] = pol_correctionRU_L1bonly(v, l1b_dat, sensor, user, ... + ICT_Param, polcorr_param, sat_name, 'alpha', dalpha); + ru_rad.dalpha = rad_polcorr - rad3; + ru_delta.dalpha = dalpha; + + %%============================================================ + %% RU STEP 6: Assess RU associated with nonlinearity correction (RU term 11) + %%============================================================ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % RU associated with nonlinearity correction + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % RU term 11: nonlinearity correction, a2 + %%%%%%%%%%%%%%%%%%%% + ru_rad.dnlc = estimate_nlc_ru_L1bonly(sensor,user,l1b_dat,ICT_Param,da2); + ru_delta.dnlc = da2.(bands{jj}); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % RU subtotals and total + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ru_rad.refl_meas = sqrt(ru_rad.dT_SSM_scan_mirror_baffle.^2 + ... + ru_rad.dT_ICT_baffle.^2 + ... + ru_rad.dT_OMA.^2 + ... + ru_rad.dT_BS_warm.^2 + ... + ru_rad.dT_BS_cold.^2); + + ru_rad.refl_mod = sqrt(ru_rad.dT_ScanBaffleCorrection.^2 + ... + ru_rad.dT_Earth.^2); + + ru_rad.pol = sqrt(ru_rad.dprpt.^2 + ... + ru_rad.dalpha.^2); + + %%============================================================ + %% RU STEP 7: Combine RU contributions via RSS + %%============================================================ + ru_rad.total = sqrt(ru_rad.de_ict.^2 + ... + ru_rad.dT_ict.^2 + ... + ru_rad.dT_SSM_scan_mirror_baffle.^2 + ... + ru_rad.dT_ICT_baffle.^2 + ... + ru_rad.dT_OMA.^2 + ... + ru_rad.dT_BS_warm.^2 + ... + ru_rad.dT_BS_cold.^2 + ... + ru_rad.dT_ScanBaffleCorrection.^2 + ... + ru_rad.dT_Earth.^2 + ... + ru_rad.dprpt.^2 + ... + ru_rad.dalpha.^2 + ... + ru_rad.dnlc.^2); + + RU.(bands{jj}).v = v; + RU.(bands{jj}).rad = rad1; + RU.(bands{jj}).rad_polcorr = rad_polcorr; + RU.(bands{jj}).rad_nopolcorr = rad_nopolcorr; + RU.(bands{jj}).ru_rad = ru_rad; + RU.(bands{jj}).ru_delta = ru_delta; + + RU_out.(bands{jj}).v = v; + RU_out.(bands{jj}).ru_delta = ru_delta; + RU_out.(bands{jj}).ru_rad_rss = RU.(bands{jj}).ru_rad.total; + RU_out.(bands{jj}).rad = RU.(bands{jj}).rad_polcorr; +end %%%%%%%%%%%%%%%%%%%% end loop over bands, jj %%%%%%%%%%%%%%%%%%%% +if saveTotalRU_FLAG == 1 + save(fullfile(pname_out,sprintf('%s.mat',fname_out)), 'RU_out'); +end +return diff --git a/RU/cris_l1b_recal_l1b_only.m b/RU/cris_l1b_recal_l1b_only.m new file mode 100644 index 0000000000000000000000000000000000000000..a879a02403597271f54c86398f476e7ba9458e2a --- /dev/null +++ b/RU/cris_l1b_recal_l1b_only.m @@ -0,0 +1,75 @@ +function [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, band, ICT_Param, ru_term, ru_value); +% +% function [rad2,B1,B2] = cris_l1b_recal_l1b_only(user, sensor, l1b_dat, band, ICT_Param, ru_term, ru_value); +% +% recalibrate radiance data using perturbed ICT radiometric model temperatures and/or +% emissivities +% +% based on recal.m (DCT/ROK 12/10/99) and adapted for use with CrIS ICT radiometric model +% +% Inputs: +% user sparse user structure +% .band +% .v +% .output_range +% sensor sparse sensor structure +% .a2_now +% .band +% l1b_dat l1b data structure needed for RU estimate +% ICT_param ICT radiometric model parameters +% ru_term string indicating ru_term to perturb +% ru_value size of perturbation +% +% Outputs: +% rad2 recalibrated radiance spectra +% B1 ICT rad model details for last obs in l1b_dat, no perturbation +% B2 ICT rad model details for last obs in l1b_dat, with perturbation +% +% Theory: +% rad1 = Re{(C_e - C_ds)./(C_ict - C_ds)}.*(L_ict1 - L_ds1) + L_ds1 +% rad2 = Re{(C_e - C_ds)./(C_ict - C_ds)}.*(L_ict2 - L_ds2) + L_ds2 +% = ((rad1-L_ds1)./(L_ict1-L_ds1)) .* (L_ict2-L_ds2) + L_ds2 +% +% where: +% C_e = complex measured spectra (Earth) +% C_ds = complex measured spectra (Deep Space) +% C_ict = complex measured spectra (Internal Cal Target) +% L_ict1 = predicted ICT radiance (no T/emiss perturbations) +% L_ds1 = predicted DS radiance (no T/emiss perturbations) +% L_ict2 = predicted ICT radiance (with perturbed T/emiss) +% L_ds2 = predicted DS radiance (with perturbed T/emiss) +% +% and +% [L_ict1,~] = predictICTrad_L1b(user2, obs_time_tai93, sci1, eng1, geo); +% [L_ict2,~] = predictICTrad_L1b(user2, obs_time_tai93, sci2, eng2, geo); +% Use of "user2" structures is a trick to compute on the user grid +% user2 = sensor;user2.v_onaxis = user.v; +% +% +% assuming perfect space view: L_ds1 = L_ds2 = 0 +% +% rad2 = (rad1 ./ (L_ict1) .* L_ict2 +% +% 2020-08-19 JKT adapted for use with NASA CrIS L1b data files, no need for L1a data +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) + +fprintf(1,'ICT rad model perturbation: %s, %f\n',ru_term,ru_value); +rad1 = l1b_dat.(sprintf('rad_%s',band)); + +[nchan,nfov,nfor,nscan] = size(rad1); +ind1 = find(user.v == user.output_range(1)); +ind2 = find(user.v == user.output_range(2)); + +user2 = sensor;user2.v_onaxis = user.v; +rad2 = nan(size(rad1)); +[ictRad1,B1] = predictICTradRU_L1bonly(user2, l1b_dat, ICT_Param, 'none', 0); +[ictRad2,B2] = predictICTradRU_L1bonly(user2, l1b_dat, ICT_Param, ru_term, ru_value); + +ictRad1 = ictRad1(ind1:ind2,:,:); +ictRad2 = ictRad2(ind1:ind2,:,:); + +for ii = 1:nfor + rad2(:,:,ii,:) = (squeeze(rad1(:,:,ii,:)) ./ ictRad1) .* ictRad2; +end + +return diff --git a/RU/estimate_nlc_ru_L1bonly.m b/RU/estimate_nlc_ru_L1bonly.m new file mode 100644 index 0000000000000000000000000000000000000000..0430b5723da15fbdc940c4524cd4652ec5ebb88f --- /dev/null +++ b/RU/estimate_nlc_ru_L1bonly.m @@ -0,0 +1,141 @@ +function nlc_ru = estimate_nlc_ru_L1bonly(sensor,user,l1b_dat,ICT_Param,da2); +% +% function [nlc_ru,rad_out,rad_out_new] = estimate_nlc_ru_L1bonly(sensor,user,l1b_dat,ICT_Param,da2); +% +% estimate radiometric uncertainty associated with nonlinearity correction (NLC) quadratic coefficient (a2) uncertainty +% +% Inputs +% sensor sparse sensor structure +% .a2_now +% .band +% user sparse user structure +% .band +% .v +% .output_range +% l1b_dat l1b data structure needed for RU estimate +% ICT_param ICT radiometric model parameters +% da2 a2 uncertainty value +% +% +% Outputs +% nlc_ru radiometric uncertainty associated with quadratic coefficient (a2) uncertainty +% +% 2020-08-19 JKT +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) + +PGA_GainALL.lw = l1b_dat.aux.pga_gain_lw; +PGA_GainALL.mw = l1b_dat.aux.pga_gain_mw; +PGA_GainALL.sw = l1b_dat.aux.pga_gain_sw; + +band = lower(user.band); +ind1 = find(user.v == user.output_range(1)); +ind2 = find(user.v == user.output_range(2)); +v = user.v(ind1:ind2); +rad_in = l1b_dat.(sprintf('rad_%s',band)); +[nchan,nfov,nfor,nscan] = size(rad_in); + +avgIT = double(l1b_dat.aux.(sprintf('ict_real_mean_%s',band)) + sqrt(-1)*l1b_dat.aux.(sprintf('ict_imag_mean_%s',band))); +avgSP = double(l1b_dat.aux.(sprintf('space_real_mean_%s',band)) + sqrt(-1)*l1b_dat.aux.(sprintf('space_imag_mean_%s',band))); +avgIT_Vdc = double(l1b_dat.aux.(sprintf('ict_vdc_%s',lower(user.band)))); +avgSP_Vdc = double(l1b_dat.aux.(sprintf('space_vdc_%s',lower(user.band)))); +ES_Vdc = double(l1b_dat.aux.(sprintf('earth_vdc_%s',lower(user.band)))); +PGA_gain = PGA_GainALL.(band); +delta_a2 = da2.(band); +user2 = sensor;user2.v_onaxis = user.v; +indx = find(user2.v_onaxis >= user.output_range(1) & user2.v_onaxis <= user.output_range(2)); +[ICTrad,~] = predictICTradRU_L1bonly(user2, l1b_dat, ICT_Param, 'none', 0); +ICTrad = ICTrad(indx,:,:); + +% make ICTrad same size as rad_in +%%%%%%%%%%%%%%%%%%%% +ICTrad2 = nan(nchan,nfov,1,nscan); +ICTrad2(:,:,1,:) = ICTrad; +ICTrad2 = repmat(ICTrad2,[1,1,nfor,1]); +clear ICTrad + +% make avgIT, avgSP same size as rad_in +% avgIT(:,:,1) and avgSP(:,:,1) are same interferometer sweep direction as even FOR ES +% avgIT(:,:,2) and avgSP(:,:,2) are same interferometer sweep direction as odd FOR ES +%%%%%%%%%%%%%%%%%%%% +%% ICT %% +jnk = zeros(nchan,nfov,nfor); +%% interferometer sweep direction 0 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 0); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 0); +jnk(:,:,scan_sweep_dir_indx) = repmat(avgIT(:,:,cal_view_sweep_dir_indx),[1,1,15]); +%% interferometer sweep direction 1 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 1); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 1); +jnk(:,:,scan_sweep_dir_indx) = repmat(avgIT(:,:,cal_view_sweep_dir_indx),[1,1,15]); +avgIT2 = repmat(jnk,[1,1,1,nscan]); +%% DS %% +jnk = zeros(nchan,nfov,nfor); +%% interferometer sweep direction 0 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 0); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 0); +jnk(:,:,scan_sweep_dir_indx) = repmat(avgSP(:,:,cal_view_sweep_dir_indx),[1,1,15]); +%% interferometer sweep direction 1 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 1); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 1); +jnk(:,:,scan_sweep_dir_indx) = repmat(avgSP(:,:,cal_view_sweep_dir_indx),[1,1,15]); +avgSP2 = repmat(jnk,[1,1,1,nscan]); +clear jnk avgIT avgSP + +% make avgIT_Vdc, avgSP_Vdc the same size as ES_Vdc +%%%%%%%%%%%%%%%%%%%% +%% ICT %% +jnk = zeros(nfov,nfor,1); +%% interferometer sweep direction 0 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 0); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 0); +jnk(:,scan_sweep_dir_indx,1) = repmat(avgIT_Vdc(:,cal_view_sweep_dir_indx),[1,15]); +%% interferometer sweep direction 1 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 1); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 1); +jnk(:,scan_sweep_dir_indx,1) = repmat(avgIT_Vdc(:,cal_view_sweep_dir_indx),[1,15]); +avgIT_Vdc2 = repmat(jnk,[1,1,nscan]); +%% DS %% +jnk = zeros(nfov,nfor,1); +%% interferometer sweep direction 0 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 0); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 0); +jnk(:,scan_sweep_dir_indx,1) = repmat(avgSP_Vdc(:,cal_view_sweep_dir_indx),[1,15]); +%% interferometer sweep direction 1 +scan_sweep_dir_indx = find(l1b_dat.scan_sweep_dir == 1); +cal_view_sweep_dir_indx = find(l1b_dat.aux.cal_view_sweep_dir == 1); +jnk(:,scan_sweep_dir_indx,1) = repmat(avgSP_Vdc(:,cal_view_sweep_dir_indx),[1,15]); +avgSP_Vdc2 = repmat(jnk,[1,1,nscan]); +clear jnk + +% estimate complex ES spectra via simple complex calibration equation, input radiance, and mean DS and ICT spectra +%%%%%%%%%%%%%%%%%%%% +cSpc = (rad_in ./ ICTrad2) .* (avgIT2 - avgSP2) + avgSP2; + +% estimate complex ES spectra with perturbed nonlinearity correction +%%%%%%%%%%%%%%%%%%%% +a2 = sensor.a2_now(:); +a2_new = a2(:) + delta_a2(:); + +cSpc_new = zeros(size(cSpc)); +avgIT2_new = zeros(size(avgIT2)); +avgSP2_new = zeros(size(avgSP2)); + +for iFOV = 1:nfov + for iES = 1:nfor + for iSCAN = 1:nscan + cSpc_new(:,iFOV,iES,iSCAN) = (1 + 2*a2_new(iFOV)*ES_Vdc(iFOV,iES,iSCAN))/... + (1 + 2*a2(iFOV)*ES_Vdc(iFOV,iES,iSCAN)) .* cSpc(:,iFOV,iES,iSCAN); + avgIT2_new(:,iFOV,iES,iSCAN) = (1 + 2*a2_new(iFOV)*avgIT_Vdc2(iFOV,iES,iSCAN))/... + (1 + 2*a2(iFOV)*avgIT_Vdc2(iFOV,iES,iSCAN)) .* avgIT2(:,iFOV,iES,iSCAN); + avgSP2_new(:,iFOV,iES,iSCAN) = (1 + 2*a2_new(iFOV)*avgSP_Vdc2(iFOV,iES,iSCAN))/... + (1 + 2*a2(iFOV)*avgSP_Vdc2(iFOV,iES,iSCAN)) .* avgSP2(:,iFOV,iES,iSCAN); + end + end +end + +rad_out = ICTrad2 .* (cSpc - avgSP2) ./ (avgIT2 - avgSP2); % rad_out - rad_in should equal zero within noise +rad_out_new = ICTrad2 .* (cSpc_new - avgSP2_new) ./ (avgIT2_new - avgSP2_new); + +nlc_ru = real(rad_out_new - rad_out); + +return; diff --git a/RU/pol_correctionRU_L1bonly.m b/RU/pol_correctionRU_L1bonly.m new file mode 100644 index 0000000000000000000000000000000000000000..a4aedcd882642d554ac10a5d40cd53bd34c956f0 --- /dev/null +++ b/RU/pol_correctionRU_L1bonly.m @@ -0,0 +1,121 @@ +function [L_polcorr,extra] = pol_correctionRU_L1bonly(v, l1b_dat, sensor, user, ICT_Param, polcorr_param, sat_name, ru_term, ru_value) +% +% function [L_polcorr,extra] = pol_correctionRU_L1bonly(v, l1b_dat, sensor, user, ICT_Param, polcorr_param, sat_name, ru_term, ru_value) +% +% Perform polarization correction, assuming the scene select mirror and sensor behave as +% a linear polarizer-analyzer pair +% apply perturbation to prpt or alpha if ru_term, ru_value are set +% +% Inputs +% v wavenumber scale +% l1b_dat uncorrected calibrated radiance +% sensor reduced sensor parameters structure +% user reduced user parameters structure +% ICT_Param ICT parameters (view factor, emissivity, etc) +% pol_corr_param ICT parameters (view factor, emissivity, etc) +% sat_name 'J1' or 'SNPP' +% ru_term term to perturb, 'prpt' or 'alpha' [optional] +% ru_value size of perturbation [optional, not valid if ru_term is empty] +% +% Outputs +% L_polcorr polarization correction calibrated radiance +% extra polarization parameter info +% +% JKT 13-Sep-2021 +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) +% + +%% Initialization +%% ------------------------------------------------------------------------- + +if isempty(ru_term) + ru_term = 'none'; + ru_value = 0; +end + +L = l1b_dat.(sprintf('rad_%s',lower(sensor.band))); + +%SSMflag = 12; +%prpt_approach_label = 'approach5'; + +%% Set delta angles (FOV and FOR dependent) +%% ------------------------------------------------------------------------- +delta_SSM = polcorr_param.delta_SSM; % already in radians + +%% calculate ICT radiance +%% ------------------------------------------------------------------------- +user2 = sensor; +user2.v_onaxis = user.v; +ind1 = find(user.v == user.output_range(1)); +ind2 = find(user.v == user.output_range(2)); +user2.v_onaxis = user2.v_onaxis(ind1:ind2); +[ictRad,~] = predictICTradRU_L1bonly(user2, l1b_dat, ICT_Param, 'none', 0); + +T_cbb = 4; +L_cbb = bt2rad(user2.v_onaxis,T_cbb); + +L_polcorr = nan(size(L)); +alph = nan(9,1); +prpt = nan(size(L,1),9); + +prpt_wn = polcorr_param.(sprintf('%s_wn',lower(sensor.band))); +prpt_allFOV = polcorr_param.(sprintf('%s_prpt',lower(sensor.band))); +alph = polcorr_param.(sprintf('%s_alph',lower(sensor.band))); +delta_cbb = polcorr_param.(sprintf('%s_delta_cbb',lower(sensor.band))); +delta_hbb = polcorr_param.(sprintf('%s_delta_hbb',lower(sensor.band))); + +%% Load polarization correction parameters (prpt, alpha, delta_cbb, delta_hbb) +%% And spectrally smooth prpt if ksmooth ~= 0 +%% ------------------------------------------------------------------------- +for iFOV = 1:9 + + if ~isempty(find(isnan(prpt_allFOV))) + error('NaN values in prpt data'); + end + % polarization prpt parameter is on NSR sampling, interpolate to current wavenumber grid if needed + prpt_in = interp1(prpt_wn(:,iFOV),prpt_allFOV(:,iFOV),v,'linear','extrap'); + prpt(:,iFOV) = prpt_in; + +end + +%% Apply RU perturbation if needed +%% ------------------------------------------------------------------------- +switch ru_term + case 'prpt' + prpt = prpt * (1+ru_value); % perturb prpt by a percentage defined by ru_value + fprintf(1,'prpt perturbation: prpt = prpt * %2.2f\n',1+ru_value); + case 'alpha' + alph = alph + ru_value; % perturb alpha by ru_value (radians) + fprintf(1,'alpha perturbation: +%1.3f rad\n',ru_value); + otherwise + fprintf(1,'nominal polarization correction\n'); +end + +%% Calculate polarization bias in calibrated radiance E_p +%% ------------------------------------------------------------------------- +E_p = nan(size(L)); +for iSCAN = 1:size(L,4) + for iFOV = 1:9 + L_ext = squeeze(L(:,iFOV,:,iSCAN)); + %% J1 does not have SSM_scan_mirror temperature + %% so approximate SSM_scan_mirror temperature with OMA_structure_input temperature + if isempty(strfind(lower(sat_name),'j1')) + B_ssm = bt2rad(user2.v_onaxis,l1b_dat.aux.ssm_scan_mirror_temp(iSCAN)); + else + B_ssm = bt2rad(user2.v_onaxis,l1b_dat.aux.oma_struct_temp_1(iSCAN)); + end + E_p(:,iFOV,:,iSCAN) = Ep_approx(prpt(:,iFOV), alph(iFOV), delta_SSM(iFOV,:), L_cbb,... + squeeze(ictRad(:,iFOV,iSCAN)), B_ssm, L_ext, delta_cbb(iFOV), delta_hbb(iFOV)); + end +end + +%% Subtract polarization bias from uncorrected calibrated radiance +%% ------------------------------------------------------------------------- +L_polcorr = L - E_p; + +extra.prpt = prpt; +extra.v = v; +extra.alpha = alph; +extra.delta_SSM = delta_SSM; + +return diff --git a/RU/predictICTradRU_L1bonly.m b/RU/predictICTradRU_L1bonly.m new file mode 100644 index 0000000000000000000000000000000000000000..1852584e77cc9f8a98bbd32af30e924ce314bc6a --- /dev/null +++ b/RU/predictICTradRU_L1bonly.m @@ -0,0 +1,57 @@ +function [ICTrad,B] = predictICTradRU_L1bonly(sensor,l1b_dat,ICT_Param,ru_term,ru_value); +% function [ICTrad,B] = predictICTradRU_L1bonly(sensor,l1b_dat,ICT_Param,ru_term,ru_value); +% +% +% Inputs +% sensor sparse spectral param structure +% .v +% .band +% .output_range +% l1b_dat l1b data structure needed for RU estimate +% ICT_param ICT radiometric model parameters +% ru_term string indicating ru_term to perturb +% ru_value size of perturbation +% +% Outputs +% ICTrad nCHAN x nFOV array of predicted ICT radiance on the +% B ICT rad model details for last obs in l1b_dat +% +% 2020-08-19 JKT adapted for use with NASA CrIS L1b data files, no need for L1a data +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) + +band = lower(sensor.band); + +% get key dimensions +[~,nFOV,nFOR,nSCAN] = size(l1b_dat.rad_lw); +nCHAN = length(sensor.v_onaxis); +%nSCAN = length(l1b_dat.aux.ict_prt1_temp); +%nFOR = size(l1b_dat.obs_time_tai93,1); + +% initialize output arrays +ICTrad = ones(nCHAN, nFOV, nSCAN) * NaN; + +%% Loop over scans and compute ICT radiance +for si = 1 : nSCAN % loop on scans + + % check that this row has some ES's + if isnan(max(l1b_dat.obs_time_tai93(1:nFOR, si)));continue;end + + T_ICT = (l1b_dat.aux.ict_prt1_temp(si) + l1b_dat.aux.ict_prt2_temp(si)) / 2; + T_CRIS.oma_struct_temp_1 = l1b_dat.aux.oma_struct_temp_1(si); + T_CRIS.oma_struct_temp_2 = l1b_dat.aux.oma_struct_temp_2(si); + T_CRIS.ssm_scan_mirror_temp = l1b_dat.aux.ssm_scan_mirror_temp(si); + T_CRIS.bs_temp = l1b_dat.aux.bs_temp(si); + T_CRIS.ssm_baffle_temp = l1b_dat.aux.ssm_baffle_temp(si); + T_CRIS.ssm_baffle_corr_temp = l1b_dat.aux.ssm_baffle_corr_temp(si); + + % Compute ICT predicted radiance + B = ICTradModelRU_L1b_aux(sensor, T_ICT, T_CRIS, ICT_Param, ru_term, ru_value); + + % Same values for all FOVs + for iFov = 1:nFOV;ICTrad(:,iFov,si) = B.total;end + +end +B.ru_term = ru_term; +B.ru_value = ru_value; + +return diff --git a/RU/rd_nc4.m b/RU/rd_nc4.m new file mode 100644 index 0000000000000000000000000000000000000000..d1140a3e10bb39375dd9659155095ef01152c882 --- /dev/null +++ b/RU/rd_nc4.m @@ -0,0 +1,43 @@ +function [root] = rd_nc4(fname); +% +% read data from netcdf4 file +% +% Inputs +% fname file name with path if not in current directory +% +% Outputs +% root structure containing contents of fname, organized by group +% +% JKT, University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) +% + +root.info = ncinfo(fname); +for ii = 1:length(root.info.Variables) + varname = root.info.Variables(ii).Name; + data = h5read(fname,['/' varname]); + root.(varname) = data; +end + +for ii = 1:length(root.info.Groups) + group.name = root.info.Groups(ii).Name; + group.info = ncinfo(fname,group.name); + for vv = 1:length(group.info.Variables) + varname = group.info.Variables(vv).Name; + root.(group.name).(varname) = h5read(fname,['/' group.name '/' varname]); + end +end + + +for ii = 1:length(root.info.Groups) + if isfield(root.info.Groups(ii),'Groups') + for jj = 1:length(root.info.Groups(ii).Groups) + group.name = root.info.Groups(ii).Groups(jj).Name; + group.info = ncinfo(fname,['/' root.info.Groups(ii).Name '/' group.name]); + for vv = 1:length(group.info.Variables) + varname = group.info.Variables(vv).Name; + root.(root.info.Groups(ii).Name).(group.name).(varname) = h5read(fname,['/' root.info.Groups(ii).Name '/' group.name '/' varname]); + end + end + end +end +return diff --git a/RU/read_l1b_for_RU.m b/RU/read_l1b_for_RU.m new file mode 100644 index 0000000000000000000000000000000000000000..7d61b9a039cd5323c6b525535f488ca8e9bf9475 --- /dev/null +++ b/RU/read_l1b_for_RU.m @@ -0,0 +1,128 @@ +function d = read_l1b_for_RU(fname); +% +% function d = read_l1b_for_RU(fname); +% +% this function reads the variables needed for the RU estimate from a NASA CrIS L1b granule (v3) +% +% Inputs +% fname filename with path +% +% Outputs +% d data structure +% .aux.measured_laser_wlen [scalar] +% .aux.neon_wlen [scalar] +% .aux.ict_prt1_temp [NSCAN x 1] +% .aux.ict_prt2_temp [NSCAN x 1] +% .aux.oma_struct_temp_1 [NSCAN x 1] +% .aux.oma_struct_temp_2 [NSCAN x 1] +% .aux.ssm_scan_mirror_temp [NSCAN x 1] +% .aux.bs_temp [NSCAN x 1] +% .aux.ssm_baffle_temp [NSCAN x 1] +% .aux.ssm_baffle_corr_temp [NSCAN x 1] +% .aux.pga_gain_lw [NFOV x 1] +% .aux.pga_gain_mw [NFOV x 1] +% .aux.pga_gain_sw [NFOV x 1] +% .aux.ict_real_mean_lw [NCHAN_LW x NFOV x 2] +% .aux.ict_real_mean_mw [NCHAN_MW x NFOV x 2] +% .aux.ict_real_mean_sw [NCHAN_SW x NFOV x 2] +% .aux.ict_imag_mean_lw [NCHAN_LW x NFOV x 2] +% .aux.ict_imag_mean_mw [NCHAN_MW x NFOV x 2] +% .aux.ict_imag_mean_sw [NCHAN_SW x NFOV x 2] +% .aux.space_real_mean_lw [NCHAN_LW x NFOV x 2] +% .aux.space_real_mean_mw [NCHAN_MW x NFOV x 2] +% .aux.space_real_mean_sw [NCHAN_SW x NFOV x 2] +% .aux.space_imag_mean_lw [NCHAN_LW x NFOV x 2] +% .aux.space_imag_mean_mw [NCHAN_MW x NFOV x 2] +% .aux.space_imag_mean_sw [NCHAN_SW x NFOV x 2] +% .aux.earth_vdc_lw [NFOV x NFOR x NSCAN] +% .aux.earth_vdc_mw [NFOV x NFOR x NSCAN] +% .aux.earth_vdc_sw [NFOV x NFOR x NSCAN] +% .aux.ict_vdc_lw [NFOV x 2] +% .aux.ict_vdc_mw [NFOV x 2] +% .aux.ict_vdc_sw [NFOV x 2] +% .aux.space_vdc_lw [NFOV x 2] +% .aux.space_vdc_mw [NFOV x 2] +% .aux.space_vdc_sw [NFOV x 2] +% .aux.cal_view_sweep_dir [2 x 1] +% .wnum_lw [NCHAN_LW x 1] +% .wnum_mw [NCHAN_MW x 1] +% .wnum_sw [NCHAN_SW x 1] +% .rad_lw [NCHAN_LW x NFOV x NFOR x NSCAN] +% .rad_mw [NCHAN_MW x NFOV x NFOR x NSCAN] +% .rad_sw [NCHAN_SW x NFOV x NFOR x NSCAN] +% .obs_time_tai93 [NFOR x NSCAN] +% .scan_sweep_dir [NFOR x 1] +% .lat [NFOV x NFOR x NSCAN] +% .lon [NFOV x NFOR x NSCAN] +% +% 2020-08-19 JKT +% University of Wisconsin-Madison Space Science and Engineering Center (UW-SSEC) + +%% aux vars +aux_var{1} = 'measured_laser_wlen'; % scalar +aux_var{end+1} = 'neon_wlen'; % scalar +aux_var{end+1} = 'ict_prt1_temp'; % NSCAN x 1 +aux_var{end+1} = 'ict_prt2_temp'; % NSCAN x 1 +aux_var{end+1} = 'oma_struct_temp_1'; % NSCAN x 1 +aux_var{end+1} = 'oma_struct_temp_2'; % NSCAN x 1 +aux_var{end+1} = 'ssm_scan_mirror_temp'; % NSCAN x 1 +aux_var{end+1} = 'bs_temp'; % NSCAN x 1 +aux_var{end+1} = 'ssm_baffle_temp'; % NSCAN x 1 +aux_var{end+1} = 'ssm_baffle_corr_temp'; % NSCAN x 1 + +aux_var{end+1} = 'pga_gain_lw'; % NFOV x 1 +aux_var{end+1} = 'pga_gain_mw'; % NFOV x 1 +aux_var{end+1} = 'pga_gain_sw'; % NFOV x 1 + +aux_var{end+1} = 'ict_real_mean_lw'; % NCHAN_LW x NFOV x 2 +aux_var{end+1} = 'ict_real_mean_mw'; % NCHAN_MW x NFOV x 2 +aux_var{end+1} = 'ict_real_mean_sw'; % NCHAN_SW x NFOV x 2 +aux_var{end+1} = 'ict_imag_mean_lw'; % NCHAN_LW x NFOV x 2 +aux_var{end+1} = 'ict_imag_mean_mw'; % NCHAN_MW x NFOV x 2 +aux_var{end+1} = 'ict_imag_mean_sw'; % NCHAN_SW x NFOV x 2 + +aux_var{end+1} = 'space_real_mean_lw'; % NCHAN_LW x NFOV x 2 +aux_var{end+1} = 'space_real_mean_mw'; % NCHAN_MW x NFOV x 2 +aux_var{end+1} = 'space_real_mean_sw'; % NCHAN_SW x NFOV x 2 +aux_var{end+1} = 'space_imag_mean_lw'; % NCHAN_LW x NFOV x 2 +aux_var{end+1} = 'space_imag_mean_mw'; % NCHAN_MW x NFOV x 2 +aux_var{end+1} = 'space_imag_mean_sw'; % NCHAN_SW x NFOV x 2 + +aux_var{end+1} = 'earth_vdc_lw'; % NFOV x NFOR x NSCAN +aux_var{end+1} = 'earth_vdc_mw'; % NFOV x NFOR x NSCAN +aux_var{end+1} = 'earth_vdc_sw'; % NFOV x NFOR x NSCAN + +aux_var{end+1} = 'ict_vdc_lw'; % NFOV x 2 +aux_var{end+1} = 'ict_vdc_mw'; % NFOV x 2 +aux_var{end+1} = 'ict_vdc_sw'; % NFOV x 2 + +aux_var{end+1} = 'space_vdc_lw'; % NFOV x 2 +aux_var{end+1} = 'space_vdc_mw'; % NFOV x 2 +aux_var{end+1} = 'space_vdc_sw'; % NFOV x 2 + +aux_var{end+1} = 'cal_view_sweep_dir'; % 2 x 1 + +%% root group vars +root_var{1} = 'wnum_lw'; % NCHAN_LW x 1 +root_var{end+1} = 'wnum_mw'; % NCHAN_MW x 1 +root_var{end+1} = 'wnum_sw'; % NCHAN_SW x 1 + +root_var{end+1} = 'rad_lw'; % NCHAN_LW x NFOV x NFOR x NSCAN +root_var{end+1} = 'rad_mw'; % NCHAN_MW x NFOV x NFOR x NSCAN +root_var{end+1} = 'rad_sw'; % NCHAN_SW x NFOV x NFOR x NSCAN + +root_var{end+1} = 'obs_time_tai93'; % NFOR x NSCAN + +root_var{end+1} = 'scan_sweep_dir'; % NFOR x 1 + +root_var{end+1} = 'lat'; % NFOV x NFOR x NSCAN +root_var{end+1} = 'lon'; % NFOV x NFOR x NSCAN + +for ii = 1:length(aux_var) + d.aux.(aux_var{ii}) = ncread(fname,sprintf('aux/%s',aux_var{ii})); +end +for ii = 1:length(root_var) + d.(root_var{ii}) = ncread(fname,sprintf('%s',root_var{ii})); +end + +return