PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/standalone/matlab/fuel_burnt_fd.m

http://github.com/jbeezley/wrf-fire
Objective C | 284 lines | 279 code | 5 blank | 0 comment | 38 complexity | 9289735d12aa28553e00f84f9d21dcbf MD5 | raw file
Possible License(s): AGPL-1.0
  1. function fuel_fraction=fuel_burnt_fd(lfn,tign,tnow,fd,fuel_time)
  2. % lfn - level set function, size (2,2)
  3. % tign - time of ignition, size (2,2)
  4. % tnow - time now
  5. % fd - mesh cell size (2)
  6. % fuel_time - time constant of fuel
  7. %
  8. % output: approximation of
  9. % /\
  10. % 1 | T(x,y)
  11. % fuel_burnt = ---------- | ( 1 - exp( - ----------- ) ) dxdy
  12. % fd(1)*fd(2) | fuel_time
  13. % \/
  14. % (x,y) in R;
  15. % L(x,y)<=0
  16. %
  17. % where R is the rectangle [0,fd(1)] * [0,fd(2)]
  18. % T is given by tign and L is given by lfn at the 4 vertices of R
  19. %
  20. % note that fuel_left = 1 - fuel_burnt
  21. %
  22. % Requirements:
  23. % exact in the case when T and L are linear
  24. % varies continuously with input
  25. % value of tign-tnow where lfn>0 ignored
  26. % assume T=0 when lfn=0
  27. figs=1:4;
  28. for i=figs,figure(i),clf,hold off,end
  29. % tign
  30. % lfn
  31. if all(lfn(:)>=0),
  32. % nothing burning, nothing to do - most common case, put it first
  33. fuel_fraction=0;
  34. elseif all(lfn(:)<=0),
  35. % all burning
  36. % T=u(1)*x+u(2)*y+u(3)
  37. % t(0,0)=tign(1,1)
  38. % t(0,msh_sz)=tign(1,2)
  39. % t(msh_sz,0)=tign(2,1)
  40. % t(msh_sz,msh_sz)=tign(2,2)
  41. % msh_sz=h
  42. % t(g/2,h/2)=sum(tign(i,i))/4
  43. % dt/dx=(1/2h)*(t10-t00+t11-t01)
  44. % dt/dy=(1/2h)*(t01-t00+t11-t10)
  45. % approximate T(x,y)=u(1)*x+u(2)*y+u(3) Using finite differences
  46. % t(x,y)=t(h/2,h/2)+(x-h/2)*dt/dx+(y-h/2)*dt/dy
  47. % u(1)=dt/dx
  48. % u(2)=dt/dy
  49. % u(3)=t(h/2,h/2)-h/2(dt/dx+dt/dy)
  50. tign_middle=(tign(1,1)+tign(1,2)+tign(2,1)+tign(2,2))/4;
  51. dt_dx=(tign(1,1)-tign(2,1)+tign(1,2)-tign(2,2))/(2*fd(1));
  52. dt_dy=(tign(1,1)-tign(1,2)+tign(2,1)-tign(2,2))/(2*fd(2));
  53. % dt_dx=(tign(2,1)-tign(1,1)+tign(2,2)-tign(1,2))/(2*fd(1));
  54. % dt_dy=(tign(1,2)-tign(1,1)+tign(2,2)-tign(2,1))/(2*fd(2));
  55. u(1)=dt_dx;
  56. u(2)=dt_dy;
  57. u(3)=tign_middle-(dt_dx*fd(1)+dt_dy*fd(2))/2;
  58. u1=u'
  59. display('fuel_burnt_fd coefficients of u')
  60. % integrate
  61. uu = -u / fuel_time;
  62. fuel_fraction = 1 - exp(uu(3)) * intexp(uu(1)*fd(1)) * intexp(uu(2)*fd(2));
  63. if(fuel_fraction<0 | fuel_fraction>1),
  64. warning('fuel_fraction should be between 0 and 1')
  65. stop
  66. end
  67. else
  68. % part of cell is burning - the interesting case
  69. % set up a list of points with the corresponding values of T and L
  70. xylist=zeros(8,2); % allocate list of points
  71. Tlist=zeros(8,1);
  72. Llist=zeros(8,1);
  73. xx=[-fd(1) fd(1) fd(1) -fd(1) -fd(1)]/2; % make center (0,0)
  74. yy=[-fd(2) -fd(2) fd(2) fd(2) -fd(2)]/2; % cyclic, counterclockwise
  75. ii=[1 2 2 1 1]; % indices of corners, cyclic, counterclockwise
  76. jj=[1 1 2 2 1];
  77. points=0;
  78. for k=1:4
  79. lfn0=lfn(ii(k),jj(k));
  80. lfn1=lfn(ii(k+1),jj(k+1));
  81. if(lfn0<=0),
  82. points=points+1;
  83. xylist(points,:)=[xx(k),yy(k)]; % add corner to list
  84. Tlist(points)=tnow-tign(ii(k),jj(k)); % time since ignition
  85. Llist(points)=lfn0;
  86. end
  87. if(lfn0*lfn1<0),
  88. points=points+1;
  89. % coordinates of intersection of fire line with segment k k+1
  90. %lfn(t)=lfn0 + t*(lfn1-lfn0)=0
  91. t=lfn0/(lfn0-lfn1);
  92. x0=xx(k)+(xx(k+1)-xx(k))*t;
  93. y0=yy(k)+(yy(k+1)-yy(k))*t;
  94. xylist(points,:)=[x0,y0];
  95. Tlist(points)=0; % now at ignition
  96. Llist(points)=0; % at fireline
  97. end
  98. end
  99. % make the lists circular and trim to size
  100. Tlist(points+1)=Tlist(1);
  101. Tlist=Tlist(1:points+1);
  102. Llist(points+1)=Llist(1);
  103. Llist=Llist(1:points+1);
  104. xylist(points+1,:)=xylist(1,:);
  105. xylist=xylist(1:points+1,:);
  106. for k=1:5,lfnk(k)=lfn(ii(k),jj(k));end
  107. figure(1)
  108. plot3(xx,yy,lfnk,'k')
  109. hold on
  110. plot3(xylist(:,1),xylist(:,2),Tlist,'m--o')
  111. plot3(xylist(:,1),xylist(:,2),Llist,'g--o')
  112. plot(xx,yy,'b')
  113. plot(xylist(:,1),xylist(:,2),'-.r+')
  114. legend('lfn on whole cell','tign-tnow on burned area',...
  115. 'lfn on burned area', 'cell boundary','burned area boundary')
  116. patch(xylist(:,1),xylist(:,2),zeros(points+1,1),250,'FaceAlpha',0.3)
  117. patch(xylist(:,1),xylist(:,2),Tlist,100,'FaceAlpha',0.3)
  118. hold off,grid on,drawnow,pause(0.5)
  119. %%%%% Approximation of the plane for lfn using finite differences
  120. % approximate L(x,y)=u(1)*x+u(2)*y+u(3)
  121. lfn_middle=(lfn(1,1)+lfn(1,2)+lfn(2,1)+lfn(2,2))/4;
  122. dt_dx=(lfn(1,1)-lfn(2,1)+lfn(1,2)-lfn(2,2))/(2*fd(1));
  123. dt_dy=(lfn(1,1)-lfn(1,2)+lfn(2,1)-lfn(2,2))/(2*fd(2));
  124. % I feel that it is right but not least squares tnow-tign
  125. u(1)=dt_dx;
  126. u(2)=dt_dy;
  127. u(3)=lfn_middle-(dt_dx*fd(1)+dt_dy*fd(2))/2;
  128. % finding the coefficient c, reminder we work over one subcell only
  129. % T(x,y)=c*L(x,y) in the sence of least squares
  130. a=0; b=0;
  131. for i=1:2
  132. for j=1:2
  133. if (lfn(i,j)<=0)
  134. a=a+lfn(i,j)*lfn(i,j);
  135. if (tign(i,j)>tnow)
  136. disp('fuel_burnt_fd: tign(i1) should be less then time_now');
  137. else
  138. b=b+(tign(i,j)-tnow)*lfn(i,j);
  139. end
  140. end
  141. end
  142. end
  143. if (a==0)
  144. display('fuel_burnt_fd: if c is on fire then one of cells should be on fire');
  145. end
  146. c=b/a;
  147. u(1)=u(1)*c;
  148. u(2)=u(2)*c;
  149. u(3)=u(3)*c;
  150. u=u'
  151. display('fuel_burnt_fd coefficients of u')
  152. nr=sqrt(u(1)*u(1)+u(2)*u(2));
  153. c=u(1)/nr;
  154. s=u(2)/nr;
  155. Q=[c, s; -s, c]; % rotation such that Q*u(1:2)=[something;0]
  156. ut=Q*u(1:2);
  157. errQ=ut(2); % should be zero
  158. ae=-ut(1)/fuel_time;
  159. ce=-u(3)/fuel_time; % -T(xt,yt)/fuel_time=ae*xt+ce
  160. cet=ce; %keep ce for later
  161. xytlist=xylist*Q'; % rotate the points in the list
  162. xt=sort(xytlist(1:points,1)); % sort ascending in x
  163. fuel_fraction=0;
  164. for k=1:points-1
  165. % integrate the vertical slice from xt1 to xt2
  166. figure(2)
  167. plot(xytlist(:,1),xytlist(:,2),'-o'),grid on,hold on
  168. xt1=xt(k);
  169. xt2=xt(k+1);
  170. plot([xt1,xt1],sum(fd)*[-1,1]/3,'y')
  171. plot([xt2,xt2],sum(fd)*[-1,1]/3,'y')
  172. if(xt2-xt1>100*eps*max(fd)), % slice of nonzero width
  173. % find slice height as h=ah*x+ch
  174. upper=0;lower=0;
  175. ah=0;ch=0;
  176. for s=1:points % pass counterclockwise
  177. xts=xytlist(s,1); % start point of the line
  178. yts=xytlist(s,2);
  179. xte=xytlist(s+1,1); % end point of the line
  180. yte=xytlist(s+1,2);
  181. if (xts>xt1 & xte > xt1) | (xts<xt2 & xte < xt2)
  182. plot([xts,xte],[yts,yte],'--k')
  183. % that is not the one
  184. else % line y=a*x+c through (xts,yts), (xte,yte)
  185. a=(yts-yte)/(xts-xte);
  186. c=(xts*yte-xte*yts)/(xts-xte);
  187. if xte<xts % upper boundary
  188. aupp=a;
  189. cupp=c;
  190. plot([xts,xte],[yts,yte],'g')
  191. ah=ah+a;
  192. ch=ch+c;
  193. upper=upper+1;
  194. else % lower boundary
  195. alow=a;
  196. clow=c;
  197. plot([xts,xte],[yts,yte],'m')
  198. lower=lower+1;
  199. end
  200. end
  201. end
  202. if(lower~=1|upper~=1),
  203. error('slice does not have one upper and one lower line')
  204. end
  205. ce=cet;% use kept ce
  206. % shift samll amounts to avoid negative fuel burnt
  207. if ae*xt1+ce > 0;%disp('ae*xt1+ce');disp(ae*xt1+ce);pause;
  208. ce=ce-(ae*xt1+ce);end;
  209. if ae*xt2+ce > 0;%disp('ae*xt2+ce');disp(ae*xt2+ce);pause;
  210. ce=ce-(ae*xt2+ce);end;
  211. ah=aupp-alow;
  212. ch=cupp-clow;
  213. % debug only
  214. patch([xt1,xt2,xt2,xt1],...
  215. [alow*[xt1,xt2]+clow,aupp*[xt2,xt1]+cupp,],k*10)
  216. axis equal,drawnow, pause(0.5)
  217. figure(3)
  218. x=[xt1:(xt2-xt1)/100:xt2];
  219. plot(x,1-exp(ae*x+ce),x,ah*x+ch,x,...
  220. (ah*x+ch).*(1-exp(ae*x+ce)),[xt1,xt2],[0,0],'+k')
  221. xlabel x,legend('burned frac','slice height','height*burned','dividers')
  222. hold on,grid on,drawnow,pause(0.5)
  223. % integrate (ah*x+ch)*(1-exp(ae*x+ce) from xt1 to xt2
  224. % numerically sound for ae->0, ae -> infty
  225. % this can be important for different model scales
  226. % esp. if someone runs the model in single precision!!
  227. % s1=int((ah*x+ch),x,xt1,xt2)
  228. s1=(xt2-xt1)*((1/2)*ah*(xt2+xt1)+ch);
  229. % s2=int((ch)*(-exp(ae*x+ce)),x,xt1,xt2)
  230. ceae=ce/ae;
  231. s2=-ch*exp(ae*(xt1+ceae))*(xt2-xt1)*intexp(ae*(xt2-xt1));
  232. % s3=int((ah*x)*(-exp(ae*x+ce)),x,xt1,xt2)
  233. % s3=int((ah*x)*(-exp(ae*(x+ceae))),x,xt1,xt2)
  234. % expand in Taylor series around ae=0
  235. % collect(expand(taylor(int(x*(-exp(ae*(x+ceae))),x,xt1,xt2)*ae^2,ae,4)/ae^2),ae)
  236. % =(1/8*xt1^4+1/3*xt1^3*ceae+1/4*xt1^2*ceae^2-1/8*xt2^4-1/3*xt2^3*ceae-1/4*xt2^2*ceae^2)*ae^2
  237. % + (-1/3*xt2^3-1/2*xt2^2*ceae+1/3*xt1^3+1/2*xt1^2*ceae)*ae
  238. % + 1/2*xt1^2-1/2*xt2^2
  239. %
  240. % coefficient at ae^2 in the expansion, after some algebra
  241. a2=(xt1-xt2)*((1/4)*(xt1+xt2)*ceae^2+(1/3)*(xt1^2+xt1*xt2+xt2^2)*ceae+(1/8)*(xt1^3+xt1*xt2^2+xt1^2*xt2+xt2^3));
  242. d=ae^4*a2;
  243. if abs(d)>eps
  244. % since ae*xt1+ce<=0 ae*xt2+ce<=0 all fine for large ae
  245. % for ae, ce -> 0 rounding error approx eps/ae^2
  246. s3=(exp(ae*(xt1+ceae))*(ae*xt1-1)-exp(ae*(xt2+ceae))*(ae*xt2-1))/ae^2;
  247. % we do not worry about rounding as xt1 -> xt2, then s3 -> 0
  248. else
  249. % coefficient at ae^1 in the expansion
  250. a1=(xt1-xt2)*((1/2)*ceae*(xt1+xt2)+(1/3)*(xt1^2+xt1*xt2+xt2^2));
  251. % coefficient at ae^0 in the expansion for ae->0
  252. a0=(1/2)*(xt1-xt2)*(xt1+xt2);
  253. s3=a0+a1*ae+a2*ae^2; % approximate the integral
  254. end
  255. s3=ah*s3;
  256. fuel_fraction=fuel_fraction+s1+s2+s3;
  257. if(fuel_fraction<0 | fuel_fraction>(fd(1)*fd(2))),
  258. fuel_fraction,(fd(1)*fd(2)),s1,s2,s3
  259. warning('fuel_fraction should be between 0 and 1')
  260. stop
  261. end
  262. end
  263. end
  264. fuel_fraction=fuel_fraction/(fd(1)*fd(2));
  265. % display('fuel_burnt_fd')
  266. %fuel_fraction=1-fuel_fraction;
  267. end
  268. for i=figs,figure(i),hold off,end
  269. end % function
  270. function s=intexp(ab)
  271. % function s=intexp(ab)
  272. % s = (1/b)*int(exp(a*x),x,0,b) ab = a*b
  273. % = 1 if a==0
  274. if eps < abs(ab)^3/6,
  275. s = (exp(ab)-1)/(ab); % rounding error approx eps/(a*b) for small a*b
  276. else
  277. s = 1 + ab/2+ab^2/6; % last term (a*b)^2/6 for small a*b
  278. end
  279. end