Inference of Model
Load and import dataset
clear all; load('./data/dc_corr.mat','dc'); addpath('./functions/'); load('coastlines.mat'); warning('off')
load('./data/BelowRadarMPS.mat');
Gneiting = @(dist,time,range_dist,range_time,delta,gamma,beta) 1./( (time./range_time).^(2.*delta) +1 ) .* exp(-(dist./range_dist).^(2.*gamma)./((time./range_time).^(2.*delta) +1).^(beta.*gamma) );
Convert the data to a simple structure
Define the data structure with all data.
data.name = {dc.name}';
data.lat = [dc.lat]';
data.lon = [dc.lon]';
data.height = [dc.height]';
data.heightDEM = [dc.heightDEM]';
data.maxrange = [dc.maxrange]';
data.nrad = numel(data.name);
data.time = dc(1).time';
data.alt = dc(1).alt';
data.NNT = datenum(repmat(data.time,1,numel(dc))-mean(cat(3,[dc.dawn],[dc.dusk]),3)) ./ datenum([dc.dawn]-[dc.dusk])*2;
Initiate empty density matrix
data_denss_sim = nan(numel(data.time), numel(dc), size(MPS{1},3));
Loop for eac radar
for i_d=1:numel(dc)
% Vertical agregation accounts for the DEM based on VolBelow.
% First, find the direction of flight of the lowest non-nan bin
[~, id] = max(~isnan(dc(i_d).dd), [], 2);
dir_lowest = dc(i_d).dd(sub2ind(size(dc(i_d).dd), (1:numel(data.time))',id));
% Transform this direction angle (0-360°) into the index of alpha (-90°-90°)
dir_lowest_round = round(dir_lowest,-1);
id_alpha=nan(size(dir_lowest_round));
id_alpha(dir_lowest_round>=0 & dir_lowest_round<90) = dir_lowest_round(dir_lowest_round>=0 & dir_lowest_round<90)+90;
id_alpha(dir_lowest_round>=90 & dir_lowest_round<270) = dir_lowest_round(dir_lowest_round>=90 & dir_lowest_round<270)-90;
id_alpha(dir_lowest_round>=270 & dir_lowest_round<360) = dir_lowest_round(dir_lowest_round>=270 & dir_lowest_round<360)-270;
id_alpha = id_alpha/10+1;
height_vol = nan(numel(data.time),numel(data.alt));
height_vol(~isnan(id_alpha),:) = dc(i_d).VolBelow(id_alpha(~isnan(id_alpha)),:);
% Integrate volume density into surface density based on the direction and corresponding volume. bird/km^2
% data.denss(:,i_d) = sum(data_dens(:,:,i_d) .* height_vol,2);
% Computing with result of MPS
tmp = dc(i_d).dens4;
data_denss_MPS = nan(size(tmp,1),size(MPS{i_d},3),size(tmp,2));
for i_real=1:size(MPS{i_d},3)
tmp(:,1:dc(i_d).scatter_lim-1) = MPS{i_d}(:,1:dc(i_d).scatter_lim-1,i_real);
data_denss_MPS(:,i_real,:) = tmp .* height_vol;
end
data_denss_sim(:,i_d,:) = sum(data_denss_MPS,3);
% Compute speed
nb_bird = permute(nanmean(data_denss_MPS,2),[1 3 2]);
w_MTR = nb_bird ./ repmat(nansum(nb_bird,2),1,size(nb_bird,2));
data.vs(:,i_d) = nansum(w_MTR .* dc(i_d).v2,2);
data.us(:,i_d) = nansum(w_MTR .* dc(i_d).u2,2);
% if data present initially
data.isdata(:,i_d)=~all(isnan(dc(i_d).DBZH),2);
end
data.vs(data.vs==0)=nan;
data.us(data.us==0)=nan;
Set data during the day to zero
data_denss_sim(repmat((data.NNT<-1 | data.NNT>1),1,1,size(data_denss_sim,3)))=nan;
data.vs(data.NNT<-1 | data.NNT>1)=nan;
data.us(data.NNT<-1 | data.NNT>1)=nan;
Remove 0 value because of the transformation
data_denss_sim(data_denss_sim==0)=nan;
Remove data when there is only a few data point (8 => 2h00) per day
tmp=dateshift(data.time,'start','day','nearest');
day_id=findgroups(datenum(tmp));
G = findgroups(day_id);
nb = splitapply(@nansum,~isnan(data_denss_sim),G);
data_denss_sim(nb(day_id,:,:)<8)=nan;
Remove time with all day or no data to save space
data.id_t=all(all(isnan(data_denss_sim),2),3);
data.time(data.id_t)=[];
data.ntime = numel(data.time);
data.NNT(data.id_t,:)=[];
data_denss_sim(data.id_t,:,:)=[];
data.vs(data.id_t,:)=[];
data.us(data.id_t,:)=[];
data.isdata(data.id_t,:)=[];
tmp=dateshift(data.time,'start','day','nearest');
[data.day_id,data.day]=findgroups(datenum(tmp));
G = findgroups(data.day_id);
nb = splitapply(@nansum,~isnan(data_denss_sim),G);
Clear variable to make space (if necessary)
clear id_t tmp1 dens_lim tmp w_MTR nb_bird data_u data_v ff dd data_dens dir_lowest dir_lowest_round height_vol id_alpha id i_d dir i_real data_denss_MPS MPS
Rain
Determine the threashold
file='./ECMWF/2018_srf.nc'; %ncdisp(file);
rain.time = datenum('01-janv-2018'):1/24:datenum('31-dec-2018 23:00');
rain.latitude=flip(double(ncread(file,'latitude')));
rain.longitude=double(ncread(file,'longitude'));
rain.tp = permute(flip(ncread(file,'tp'),2) , [2 1 3]); % Total precipitation [m] (accumulation over the hour ending at the forcast step)
F = griddedInterpolant({rain.latitude,rain.longitude,datenum(rain.time)},rain.tp);
for i_d=1:numel(dc)
data.rain(:,i_d) = F({data.lat(i_d),data.lon(i_d),datenum(data.time)});
end
Consider only night time, where data is present (i.e. DBZH available)
consider = data.NNT>-1 & data.NNT<1 & data.isdata;
Bird density
tmp = data_denss_sim(:,:,1);
Figure to illustrate
% figure; hold on;
% histogram(data.rain(isnan(tmp)&consider))
% histogram(data.rain(~isnan(tmp)&consider))
% set(gca,'YScale','log')
% figure; scatter(data.rain(consider), tmp(consider),'k.')
figure('position',[0 0 1000 400]); hold on;
plot(tmp(:,2))
plot(data.isdata(:,2)*100)
yyaxis right;
plot(data.rain(:,2))
thr=0:0.00001:0.005;
score=nan(3,numel(thr));
for i=1:numel(thr)
rain_id=data.rain>=thr(i);
score(1,i)=mean(isnan(tmp(rain_id&consider)));
score(2,i)=mean(isnan(tmp(~rain_id&consider)));
score(3,i)=sum(rain_id(:)&consider(:))/sum(consider(:));
end
figure('position',[0 0 1000 400]); plot(thr,score'); xlabel('threshold value [m/hr]'); ylabel('%')
legend('% of data nan amongst the eliminated data','% of nan in the non-eliminated data')
This threashold value is defined at 1 mm/hr -> 0.001 m at the hourly resolution of the total precipitation according to https://confluence.ecmwf.int//display/CKB/ERA5+data+documentation#ERA5datadocumentation-Meanratesandaccumulations
data.mask_rain_thr=0.001;
Clear variable
clear rain F file consider tmp score
Transformation of data
Raw data very skew, transformation to normal space using a kernel-based density fit.
Transformation does not work for dens=0. remove for the fit
pd=fitdist(data_denss_sim(:),'Kernel','Support','positive');
Too many data for the forward transformation. Reduce the site of the data to transform using only the value rounded to 2 decimal. Compute the transformation of the MPS simulation and compute the std
trans.dens_axis = logspace(log10(min(data_denss_sim(:))), log10(max(data_denss_sim(:))),1000);
trans.denst_axis = norminv(cdf(pd,trans.dens_axis));
trans.dens_axis([false diff(trans.denst_axis)==0])=[];
trans.denst_axis([false diff(trans.denst_axis)==0])=[];
data.denst = interp1(trans.dens_axis,trans.denst_axis,data_denss_sim,'pchip');
data.denst_m = nanmean(data.denst,3);
% data.denst_s = nanstd(data.denst,[],3);
inverse: SUPER SLOW
% data.dens_m = icdf(pd,normcdf(data.denst_m));
data.dens_m = interp1(trans.denst_axis,trans.dens_axis,data.denst_m,'pchip');
Figure
figure('position',[0 0 1000 400]); hold on;
subplot(1,2,1); hold on;
histogram(data_denss_sim(:),'Normalization','probability'); plot(0:500,pdf(pd,0:500))
tmp = nanmean(data.denst,3);
subplot(1,2,2); histfit(tmp(:),100)
clear pd
Block decompostion
We compute the parameters of the trends and covariance function on each temporal subset (=block) of the dataset. Each block of the dataset is of size data_block days and add some overlap with previous and next day of block_overlap days.
data.block.date = [737121 737184 737273 737384]; % '13-Feb-2018', '02-Mar-2018', '23-Apr-2018','24-Sep-2018', '20-Nov-2018', '01-Jan-2019'
data.block.date_str={'Spring (02-Mar - 04-May)','Summer (4-May - 1-Aug)','Autumn (1-Aug - 20-Nov)','Winter (20-Nov - 02-Mar)'};
data.block.col = [[81 161 114];[206 202 105];[213 122 93];[85 126 170]]/255;
These date are defined with the figure below
U=nanmean(splitapply(@nanmean, (data.us*60*60/1000.*data.dens_m), data.day_id),2);
V=nanmean(splitapply(@nanmean, (data.vs*60*60/1000.*data.dens_m), data.day_id),2);
MTR = sqrt(U.^2+V.^2);
figure('position',[0 0 1000 400]); hold on
% Background color
for i_b=1:numel(data.block.date)-1
fill([data.block.date(i_b)-.5 data.block.date(i_b)-.5 data.block.date(i_b+1)-.5 data.block.date(i_b+1)-.5],[4.5 0 0 4.5]*1000,data.block.col(i_b,:))
end
fill([min(data.day)-.5 min(data.day)-.5 data.block.date(1) data.block.date(1)-.5],[4.5 0 0 4.5]*1000,data.block.col(4,:))
fill([data.block.date(end)-.5 data.block.date(end)-.5 max(data.day) max(data.day)-.5],[4.5 0 0 4.5]*1000,data.block.col(4,:))
% MTR
bar(data.day,MTR,'k')
ylabel('Average movement of bird per day [bird/km/hr] (MTR)');
% MTR direction
yyaxis right; plot(data.day,atan2d(V,U),'.','Color',[.2 .2 .2]);
ylabel('Direction of the movement (0°)');
line([data.day(1) data.day(end)],[0 0],'Color',[.2 .2 .2]); text(data.day(1),8,'East','Color',[.2 .2 .2])
line([data.day(1) data.day(end)],[90 90],'Color',[.2 .2 .2]); text(data.day(1),98,'North','Color',[.2 .2 .2])
line([data.day(1) data.day(end)],[-180 -180],'Color',[.2 .2 .2]); text(data.day(1),-172,'West','Color',[.2 .2 .2])
line([data.day(1) data.day(end)],[-90 -90],'Color',[.2 .2 .2]); text(data.day(1),-82,'South','Color',[.2 .2 .2])
ylim([-180 180]);
datetick('x'); xlabel('Date'); ax = gca;ax.YAxis(1).Color = 'k';ax.YAxis(2).Color = 'k'; axis tight;
for i_b=1:numel(data.block.date)
if i_b==numel(data.block.date)
data.b(datenum(data.time)>=data.block.date(4) | datenum(data.time)<data.block.date(1)) = i_b;
else
data.b(datenum(data.time)>=data.block.date(i_b) & datenum(data.time)<data.block.date(i_b+1)) = i_b;
end
end
Average Daily
Compute the radar and day index (t and r)
multi.t = data.day;
multi.r = 1:data.nrad;
[multi.R,multi.T]=meshgrid(multi.r,multi.t);
Compute the daily average
G = findgroups(data.day_id);
multi.M = splitapply(@nanmean,data.denst,G);
nb = splitapply(@nansum,~isnan(data.denst),G);
multi.M_m = mean(multi.M,3);
multi.M_var = var(multi.M,[],3);
multi.isnan = isnan(multi.M_m);
Figure
figure('position',[0 0 1000 400]); hold on;
subplot(2,1,1); imagesc(multi.M_m')
subplot(2,1,2); imagesc(sqrt(multi.M_var)'); caxis([0 .1])
Attribute block
multi.b = nan(size(multi.t));
for i_b=1:numel(data.block.date)
if i_b==numel(data.block.date)
multi.b(multi.t>=data.block.date(i_b) | multi.t<data.block.date(1)) = i_b;
else
multi.b(multi.t>=data.block.date(i_b) & multi.t<data.block.date(i_b+1)) = i_b;
end
end
multi.B = repmat(multi.b,1,data.nrad);
data.day_b = multi.b;
Trend
The trend is commputed as a polynomila of degree poly_t_degree in the time axis and poly_t_degree in space (2D).
multi_poly_t_degree=0;
multi_poly_d_degree=1;
The trend is determined with a Generalized Linear Square regression (GLS), where the following linear problem is solved
,
where are the coefficient of the polynomes, C is the covariance matrix of the data y. Xis the Vandermonde matrix for the time and coordinate of the data y. In our case:
X = trend(multi.T,data.lat(multi.R),data.lon(multi.R),multi_poly_t_degree,multi_poly_d_degree);
C = diag(1+multi.M_var(:));
y = multi.M_m(:);
We can then create the forward function of the trend which given any location (time and coordinate) and polynomial coefficinet w return the value of the trend
multi.f_trend = @(t,lat,lon,beta) reshape(trend(t(:),lat(:),lon(:),multi_poly_t_degree,multi_poly_d_degree) * beta(:), size(t));
We will then compute the detrended value of the multi-night scale componenent
multi.M_mn=nan(size(multi.M_m));
multi.beta = nan(multi_poly_t_degree+ (multi_poly_d_degree)*2+1,numel(data.block.date));
idm_b=cell(numel(data.block.date),1);
We loop over all block...
for i_b=1:numel(data.block.date)
... first compute the block index....
id = find(~multi.isnan & multi.B==i_b);
.... and then, the trend coefficient
multi.beta(:,i_b) = ((X(id,:)'*(C(id,id)\X(id,:)))\X(id,:)')*(C(id,id)\y(id)); % GLS
Figure
if false
figure('position',[0 0 1000 400]); hold on;
t_tmp = sort(unique(multi.T(id)));
plot(t_tmp,multi.f_trend(t_tmp,mean(data.lat)*ones(numel(t_tmp),1),mean(data.lon)*ones(numel(t_tmp),1), multi.beta(:,i_b)),'-r')
plot(multi.T(id),y(id),'.g')
plot(multi.T(id),y(id),'.k')
figure('position',[0 0 1000 400]);
h=worldmap([floor(min(data.lat)) ceil(max(data.lat))], [floor(min(data.lon)) ceil(max(data.lon))]);
setm(h,'frame','on','grid','off'); set(findall(h,'Tag','MLabel'),'visible','off'); set(findall(h,'Tag','PLabel'),'visible','off')
[lat_tmp,lon_tmp]=meshgrid(floor(min(data.lat)):.2:ceil(max(data.lat)), floor(min(data.lon)):.2:ceil(max(data.lon)));
S=multi.f_trend(mean(multi.T(id))*ones(size(lat_tmp)),lat_tmp,lon_tmp,multi.beta(:,i_b));
surfm(lat_tmp,lon_tmp,S)
plotm(coastlat, coastlon,'k'); geoshow('worldrivers.shp','Color', 'blue')
[G,id]=findgroups(multi.R(id));
scatterm(data.lat(id),data.lon(id),100,splitapply(@mean,y(id), G),'filled','MarkerEdgeColor','k');
caxis([min(y(id)) max(y(id))])
end
Compute the de-trended value
multi.M_mn(id) = multi.M_m(id)-multi.f_trend(multi.T(id),data.lat(multi.R(id)),data.lon(multi.R(id)),multi.beta(:,i_b));
end
Figure
% col = [[0.0235 0.4824 0.2157];[0.7333 0.7059 0.1569];[0.7725 0.2549 0.1020];[0.0510 0.2784 0.5255]];
figure('position',[0 0 1000 400]); hold on;
for i_b=1:numel(data.block.date)-1
fill([data.block.date(i_b) data.block.date(i_b) data.block.date(i_b+1) data.block.date(i_b+1)],[4 -4 -4 4],data.block.col(i_b,:))
end
fill([min(data.day) min(data.day) data.block.date(1) data.block.date(1)],[4 -4 -4 4],data.block.col(4,:))
fill([data.block.date(end) data.block.date(end) max(data.day) max(data.day) ],[4 -4 -4 4],data.block.col(4,:))
plot(multi.T(:), y,'.k')
for i_b=1:numel(data.block.date)
id = find(~multi.isnan & multi.B==i_b);
t_tmp = sort(unique(multi.T(id)));
plot(t_tmp, multi.f_trend(t_tmp,mean(data.lat(multi.R(id)))*ones(numel(t_tmp),1),mean(data.lon(multi.R(id)))*ones(numel(t_tmp),1), multi.beta(:,i_b)),'-r','Linewidth',2)
end
datetick('x'); ylim([-4 4]); axis tight;
figure('position',[0 0 1000 400]); hold on;
[LAT, LON] = meshgrid(floor(min(data.lat)):.1:ceil(max(data.lat)),floor(min(data.lon)):.1:ceil(max(data.lon)));
for i_b=1:numel(data.block.date)
id = find(~multi.isnan & multi.B==i_b);
subplot(2,2,i_b,'Color',data.block.col(i_b,:)); hold on; h=worldmap([floor(min(data.lat)) ceil(max(data.lat))], [floor(min(data.lon)) ceil(max(data.lon))]);
setm(h,'frame','on','grid','off'); set(findall(h,'Tag','MLabel'),'visible','off'); set(findall(h,'Tag','PLabel'),'visible','off')
surfm(LAT,LON,multi.f_trend(mean(multi.T(id))*ones(size(LAT)),LAT,LON,multi.beta(:,i_b)))
plotm(coastlat, coastlon,'k'); geoshow('worldrivers.shp','Color', 'blue')
[G,tmp]=findgroups(multi.R(id));
tmp2 = splitapply(@mean,multi.M(id),G);
scatterm(data.lat(tmp),data.lon(tmp),80,tmp2,'filled','MarkerEdgeColor','k');
title(data.block.date_str{i_b},'Color',data.block.col(i_b,:) ); caxis([min(tmp2) max(tmp2)])
colorbar
end
figure('position',[0 0 1000 400]); imagesc(multi.M_mn'); xlabel('Time'); ylabel('Radar')
Covariance Multi
cov.d=[0 1 150 200 300 400 500 750 1000 2000];
cov.t=[0 1 2 3 4 5 10 20];
[cov.D,cov.T] = meshgrid(cov.d(1:end-1)+diff(cov.d)/2,cov.t(1:end-1));
cov.D_emp=nan(size(cov.D,1),size(cov.D,2),numel(data.block.date)-1);
cov.T_emp = cov.D_emp;
cov.emp_grid=nan(size(cov.D));
cov.nb=nan(numel(data.block.date)-1,1);
for i_b=1:numel(data.block.date)
id = find(~multi.isnan & multi.B==i_b);
cov.nb(i_b)=sum(id(:));
Dtime=squareform(pdist(multi.T(id)));
Ddist=squareform(pdist([data.lat(multi.R(id)) data.lon(multi.R(id))],@lldistkm));
cov_emp = bsxfun(@times, multi.M_mn(id)', multi.M_mn(id));
for i_t=1:numel(cov.t)-1
for i_d=1:numel(cov.d)-1
id = Dtime>=cov.t(i_t) & Dtime<cov.t(i_t+1) & Ddist>=cov.d(i_d) & Ddist<cov.d(i_d+1);
cov.D_emp(i_t,i_d,i_b) = nanmean(Ddist(id));
cov.T_emp(i_t,i_d,i_b) = nanmean(Dtime(id));
cov.emp_grid(i_t,i_d,i_b) = nanmean( cov_emp(id) );
end
end
end
Figure
figure('position',[0 0 1000 400]);
for i_b = 1:numel(data.block.date)
subplot(2,2,i_b); surf(cov.D_emp(:,:,i_b),cov.T_emp(:,:,i_b),cov.emp_grid(:,:,i_b));
xlabel('Distance [km]'); ylabel('Time [days]'); title(data.block.date_str{i_b},'Color',data.block.col(i_b,:));
subplot(2,2,i_b,'color',data.block.col(i_b,:));
end
Covariance function fit
Gneiting_fit = @(parm,i_b) parm(1)*(cov.D_emp(:,:,i_b)==0 & cov.T_emp(:,:,i_b)==0) + parm(2)*(cov.D_emp(:,:,i_b)==0) + parm(3).*Gneiting(cov.D_emp(:,:,i_b),cov.T_emp(:,:,i_b),parm(4),parm(5),parm(6),parm(7),parm(8));
parm0 =[.05 0 .2 500 5 .2 .2 .2 ];
parm_min=[0.1 0.05 0 0.0001 0 0.6 0.6 0]';
for i_b=1:numel(data.block.date)
id = find(~multi.isnan & multi.B==i_b);
parm_max=[nancov(multi.M_mn(id)) nancov(multi.M_mn(id)) nancov(multi.M_mn(id)) 3000 10 1 1 1 ]';
A = -[1 1 0 0 0 0 0 0];
b = -0.9*(nancov(multi.M_mn(id))-max(cov.emp_grid(1,2,i_b),cov.emp_grid(2,1,i_b)));
Aeq=[1 1 1 0 0 0 0 0];
beq=nancov(multi.M_mn(id));
rmse = @(parm) nansum(nansum( 1000*max(cov.emp_grid(:,:,i_b),0.01).*( (Gneiting_fit(parm,i_b) - cov.emp_grid(:,:,i_b)).^2 ) )); %
multi.cov.parm(:,i_b) = fmincon(rmse, parm0, A, b, Aeq, beq, parm_min, parm_max, [], optimoptions('fmincon','Display','off'));
cov.parm0=multi.cov.parm(:,i_b);
end
Display parameters of covariance
fprintf(['nugget(0,0)\t nugget(0,:)\t var\t range distance[km]\t range time[day]\t shape distance (delta)\t shape time (gamma)\t separability (beta)\n%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f\n%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f\n%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f\n%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f'],multi.cov.parm)
Construct the covariance function as inline function.
multi.cov.Cn = @(D,T,parm) parm(1)*(D==0 & T==0) + parm(2)*(D==0) + parm(3).*Gneiting(D,T,parm(4),parm(5),parm(6),parm(7),parm(8));
multi.cov.C = @(D,T,parm) parm(3).*Gneiting(D,T,parm(4),parm(5),parm(6),parm(7),parm(8));
Illustration of the fitted covariance function
[tmpD,tmpT] = meshgrid(cov.d(1):1:cov.d(end),cov.t(1):0.1:cov.t(end));
figure('position',[0 0 1000 400]);
for i_b = 1:numel(data.block.date)
subplot(2,2,i_b); hold on
s=surf(tmpD,tmpT,multi.cov.Cn(tmpD, tmpT,multi.cov.parm(:,i_b))); s.EdgeColor='none';
surf(cov.D_emp(:,:,i_b),cov.T_emp(:,:,i_b),cov.emp_grid(:,:,i_b));
xlabel('Distance [km]'); ylabel('Time [days]'); title(data.block.date_str{i_b},'Color',data.block.col(i_b,:)); view(3);
plot3([0 0],[0 0],[multi.cov.parm(3,i_b) sum(multi.cov.parm(2:3,i_b))],'r', 'linewidth',2)
plot3([0 0],[0 0],[sum(multi.cov.parm(2:3,i_b)) sum(multi.cov.parm(1:3,i_b))],'g', 'linewidth',2)
subplot(2,2,i_b,'color',data.block.col(i_b,:));
end
Clear all un-necessary variable
%clear C cov* Ddist Dtime G Gneiting_fit h i* L* parm* rmse s tmp* X y ans
Intra-night scale
At the intra-night scale, we model the the fluctuation around the multi-night scale
% save memory intra.I = data.denst-multi.M(data.day_id,:,:);
intra.I_m = nanmean(data.denst-multi.M(data.day_id,:,:),3);
intra.I_var = nanvar(data.denst-multi.M(data.day_id,:,:),[],3);
intra.I_var(intra.I_m<-1.5)=nan;
intra.I_m(intra.I_m<-1.5)=nan;
intra_isnan = isnan(intra.I_m);
Block decomposition
intra.b = nan(size(data.time));
for i_b=1:numel(data.block.date)
if i_b==numel(data.block.date)
intra.b(datenum(data.time)>=data.block.date(4) | datenum(data.time)<data.block.date(1)) = i_b;
else
intra.b(datenum(data.time)>=data.block.date(i_b) & datenum(data.time)<data.block.date(i_b+1)) = i_b;
end
end
intra.b = uint8(intra.b);
intra_B = repmat(intra.b,1,data.nrad);
The most important trend at the intra-night scale is along the the night. We use a polynomial function to account for this smooth variation
intra_poly_degree=8;
X=bsxfun(@power,data.NNT(:),intra_poly_degree:-1:0);
C=spdiags(1+intra.I_var(:), 0, numel(intra.I_var), numel(intra.I_var));
intra.f_trend = @(t,beta) reshape(bsxfun(@power,t(:),intra_poly_degree:-1:0) * beta(:),size(t));
We will then compute the detrended value of the multi-night scale componenent
I_mn_tmp=nan(size(intra.I_m));
intra.beta = nan(intra_poly_degree+1,numel(data.block.date));
We loop over all block...
for i_b=1:numel(data.block.date)
id = intra_B==i_b & ~intra_isnan;
intra.beta(:,i_b) = ((X(id,:)'*(C(id,id)\X(id,:)))\X(id,:)')*(C(id,id)\intra.I_m(id)); % GLS
I_mn_tmp(id) = intra.I_m(id) - intra.f_trend(data.NNT(id),intra.beta(:,i_b));
end
NNT_axis=-1:.01:1;
figure('position',[0 0 1000 400]);
for i_b = 1:numel(data.block.date)
id = intra_B==i_b & ~intra_isnan;
subplot(2,2,i_b,'color',data.block.col(i_b,:)); hold on
plot(data.NNT(id),intra.I_m(id),'.k');
plot(NNT_axis, intra.f_trend(NNT_axis, intra.beta(:,i_b)),'-r','linewidth',2);
title(data.block.date_str{i_b},'color',data.block.col(i_b,:));
subplot(2,2,i_b,'color',data.block.col(i_b,:));
xlabel('Normalized Night Time (NNT)'); ylabel('B^p-M-\mu'); ylim([-4 2]); xlim([-1 1])
end
figure('position',[0 0 1000 400]);
for i_r = 1:data.nrad
subplot(5,8,i_r);
plot(data.NNT(:,i_r),intra.I_m(:,i_r),'.k');
title(data.name(i_r));
xlabel('Normalized Night Time (NNT)'); ylabel('B^p-M-\mu'); ylim([-4 2]); xlim([-1 1])
end
In addition to present a trend of the mean, the intra-night components also contains a non-stationarity of variance along the night (see figure below). We fit another polynomial function to normalize the variance
intra_poly_degree_v=6;
X=bsxfun(@power,data.NNT(:),intra_poly_degree_v:-1:0);
intra.f_trend_v = @(t,beta_v) reshape(bsxfun(@power,t(:),intra_poly_degree_v:-1:0) * beta_v(:),size(t));
We will then compute the detrended value of the multi-night scale componenent
intra_I_var_n=nan(size(intra.I_m));
intra.beta_v = nan(intra_poly_degree_v+1,numel(data.block.date));
We loop over all block...
for i_b=1:numel(data.block.date)
id = intra_B==i_b & ~intra_isnan;
intra.beta_v(:,i_b) = (X(id,:)'*X(id,:))\(X(id,:)'*I_mn_tmp(id).^2);
intra_I_var_n(id) = intra.f_trend_v(data.NNT(id),intra.beta_v(:,i_b));
end
Illustration
NNT_axis=-1:.01:1;
figure('position',[0 0 1000 400]);
for i_b = 1:numel(data.block.date)
id = intra_B==i_b & ~intra_isnan;
subplot(2,2,i_b,'color',data.block.col(i_b,:)); hold on
plot(data.NNT(id),I_mn_tmp(id).^2,'.k');
plot(NNT_axis, intra.f_trend_v(NNT_axis,intra.beta_v(:,i_b)),'-r','linewidth',2);
title(data.block.date_str{i_b},'color',data.block.col(i_b,:));
subplot(2,2,i_b,'color',data.block.col(i_b,:));
xlabel('Normalized Night Time (NNT)'); ylabel('var(B^p-M-\mu-\iota)');ylim([0 3]); xlim([-1 1])
end
Finally, combining the polynomial of the curve and the correction for variance, we find the de-trended intra-night scale I
intra.I_mn = I_mn_tmp(~intra_isnan) ./ sqrt(intra_I_var_n(~intra_isnan));
intra.I_varn = intra.I_var(~intra_isnan) ./ intra_I_var_n(~intra_isnan);
Check the histogram
figure('position',[0 0 1000 400]); histogram(intra.I_mn);
% clear C y i_* X id I_mn_tmp intra_I_var_n
4.2 Covariance function of
Built the matrix of distances of the data. Distence (or difference) in lattitude, longitude, time and value.
Ddist_sm = squareform(pdist([data.lat data.lon], @lldistkm));
tmp=repmat(1:data.nrad,data.ntime,1);
intra_radar = tmp(~intra_isnan);
tmp=repmat(data.day(data.day_id),1,data.nrad);
intra_day = tmp(~intra_isnan);
tmp=repmat(datenum(data.time),1,data.nrad);
intra_time = tmp(~intra_isnan);
cov.d=[0 1 100 150 200 250 300 600 1000];
cov.t=[0 .01 .02 .05 .07 .1 .2];
[cov.D,cov.T]=meshgrid(cov.d(1:end-1)+diff(cov.d)/2,cov.t(1:end-1)+diff(cov.t)/2);
cov.D_emp=nan(size(cov.D,1),size(cov.D,2),numel(data.block.date));
cov.T_emp=nan(size(cov.D_emp));
cov.emp_grid=nan(size(cov.D_emp));
for i_b=1:numel(data.block.date)
D = nan(1000000000,2);
Did = zeros(1000000000,2,'uint32');
i=0;
for i_t=data.day(data.day_b==i_b)'
id = find(intra_day==i_t);
tmp1 = [reshape(Ddist_sm(intra_radar(id),intra_radar(id)),[],1) reshape(squareform(pdist(intra_time(id))),[],1)];
tmp2 = [uint32(repmat(id,numel(id),1)) uint32(repelem(id,numel(id)))];
B = tril(ones(numel(id)));
id2=B(:)==1 & tmp1(:,1)<cov.d(end) & tmp1(:,2)<cov.t(end);
D(i+(1:sum(id2)),:)=tmp1(id2,:);
Did(i+(1:sum(id2)),:)=tmp2(id2,:);
i=i+sum(id2);
end
D=D(1:i,:);
Did=Did(1:i,:);
for i_d=1:numel(cov.d)-1
id1 = find(D(:,1)>=cov.d(i_d) & D(:,1)<cov.d(i_d+1));
for i_t=1:numel(cov.t)-1
id2 = id1(D(id1,2)>=cov.t(i_t) & D(id1,2)<cov.t(i_t+1));
cov.emp_grid(i_t,i_d,i_b)= mean(intra.I_mn(Did(id2,1)) .* intra.I_mn(Did(id2,2)));
cov.D_emp(i_t,i_d,i_b) = nanmean(D(id2,1));
cov.T_emp(i_t,i_d,i_b) = nanmean(D(id2,2));
end
end
end
Figure
figure('position',[0 0 1000 400]);
for i_b = 1:numel(data.block.date)
subplot(2,2,i_b); surf(cov.D_emp(:,:,i_b),cov.T_emp(:,:,i_b),cov.emp_grid(:,:,i_b));
xlabel('Distance [km]'); ylabel('Time [days]'); title(data.block.date_str{i_b},'Color',data.block.col(i_b,:));
subplot(2,2,i_b,'color',data.block.col(i_b,:));
end
Gneiting_fit = @(parm,i_b) parm(1)*(cov.D_emp(:,:,i_b)==0 & cov.T_emp(:,:,i_b)==0) + parm(2)*(cov.D_emp(:,:,i_b)==0) + parm(3).*Gneiting(cov.D_emp(:,:,i_b),cov.T_emp(:,:,i_b),parm(4),parm(5),parm(6),parm(7), parm(8));
parm0 =[.05 .05 .8 500 5 .2 .2 .2 ];
parm_min=[.05 .05 0 0.0001 0 0.6 0.6 0 ]';
for i_b=1:numel(data.block.date)
parm_max = [cov.emp_grid(1,1,i_b) cov.emp_grid(1,1,i_b) cov.emp_grid(1,1,i_b) 3000 10 1 1 1 ]';
A = -[1 1 0 0 0 0 0 0];
b = -0.9*(cov.emp_grid(1,1,i_b)-max(cov.emp_grid(1,2,i_b)));
Aeq=[1 1 1 0 0 0 0 0];
beq=cov.emp_grid(1,1,i_b);
rmse = @(parm) nansum(nansum( ( 1000*max(cov.emp_grid(:,:,i_b),0.01) .* (Gneiting_fit(parm,i_b) - cov.emp_grid(:,:,i_b)).^2 ) ));
intra.cov.parm(:,i_b) = fmincon(rmse,parm0,A, b, Aeq, beq,parm_min,parm_max,[],optimoptions('fmincon','Display','off'));
parm0=intra.cov.parm(:,i_b);
end
Display parameters of covariance
fprintf(['nugget(0,0)\t nugget(0,:)\t var\t range distance[km]\t range time[day]\t shape distance (delta)\t shape time (gamma)\t separability (beta)\n' ...
'%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f\n' ...
'%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f\n' ...
'%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f\n' ...
'%.3f\t\t %.3f\t\t %.3f\t %.3f\t\t %.3f\t\t\t %.3f\t\t\t %.3f\t\t\t %.3f'],intra.cov.parm)
Construct the covariance function as inline function.
intra.cov.Cn = @(D,T,parm) parm(1)*(D==0 & T==0) + parm(2)*(D==0) + parm(3).*Gneiting(D,T,parm(4),parm(5),parm(6),parm(7),parm(8));
intra.cov.C = @(D,T,parm) parm(3).*Gneiting(D,T,parm(4),parm(5),parm(6),parm(7),parm(8));
Figure
[tmpD,tmpT] = meshgrid(cov.d(1):1:cov.d(end),cov.t(1):0.1:cov.t(end));
figure('position',[0 0 1000 400]);
for i_b = 1:numel(data.block.date)
subplot(2,2,i_b); hold on
s=surf(tmpD,tmpT,intra.cov.Cn(tmpD, tmpT,intra.cov.parm(:,i_b))); s.EdgeColor='none';
surf(cov.D_emp(:,:,i_b),cov.T_emp(:,:,i_b),cov.emp_grid(:,:,i_b));
xlabel('Distance [km]'); ylabel('Time [days]'); title(data.block.date_str{i_b},'Color',data.block.col(i_b,:)); view(3);
plot3([0 0],[0 0],[intra.cov.parm(3,i_b) sum(intra.cov.parm(2:3,i_b))],'r', 'linewidth',2)
plot3([0 0],[0 0],[sum(intra.cov.parm(2:3,i_b)) sum(intra.cov.parm(1:3,i_b))],'g', 'linewidth',2)
subplot(2,2,i_b,'color',data.block.col(i_b,:));
end
5. Save
Save the parameters of the model.
save('data/Density_inference.mat','data','multi','intra','trans','-v7.3')
% load('data/Density_inference.mat')
% writetable(data,'data/Density_data.csv')