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

/standalone/matlab/fuel_burnt_debug.m

http://github.com/jbeezley/wrf-fire
Objective C | 236 lines | 234 code | 2 blank | 0 comment | 33 complexity | c5de7897c1cbeea50b49296aa8d02b27 MD5 | raw file
Possible License(s): AGPL-1.0
  1. function fuel_fraction=fuel_burnt(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. if all(lfn(:)>=0),
  30. % nothing burning, nothing to do - most common case, put it first
  31. fuel_fraction=0;
  32. elseif all(lfn(:)<=0),
  33. % all burning
  34. % T=u(1)*x+u(2)*y+u(3)
  35. % set up least squares(A*u-v)*inv(C)*(A*u-v)->min
  36. A=[0, 0, 1;
  37. fd(1), 0, 1;
  38. 0, fd(2), 1;
  39. fd(1),fd(2), 1];
  40. v=tnow-tign(:); % time from ignition
  41. rw=2*ones(4,1);
  42. u = lscov(A,v,rw); % solve least squares to get coeffs of T
  43. residual=norm(A*u-v); % zero if T is linear
  44. % integrate
  45. uu = -u / fuel_time;
  46. fuel_fraction = 1 - exp(uu(3)) * intexp(uu(1)*fd(1)) * intexp(uu(2)*fd(2));
  47. if(fuel_fraction<0 | fuel_fraction>1),
  48. warning('fuel_fraction should be between 0 and 1')
  49. end
  50. else
  51. % part of cell is burning - the interesting case
  52. % set up a list of points with the corresponding values of T and L
  53. xylist=zeros(8,2); % allocate list of points
  54. Tlist=zeros(8,1);
  55. Llist=zeros(8,1);
  56. xx=[-fd(1) fd(1) fd(1) -fd(1) -fd(1)]/2; % make center (0,0)
  57. yy=[-fd(2) -fd(2) fd(2) fd(2) -fd(2)]/2; % cyclic, counterclockwise
  58. ii=[1 2 2 1 1]; % indices of corners, cyclic, counterclockwise
  59. jj=[1 1 2 2 1];
  60. points=0;
  61. for k=1:4
  62. lfn0=lfn(ii(k),jj(k));
  63. lfn1=lfn(ii(k+1),jj(k+1));
  64. if(lfn0<=0),
  65. points=points+1;
  66. xylist(points,:)=[xx(k),yy(k)]; % add corner to list
  67. Tlist(points)=tnow-tign(ii(k),jj(k)); % time since ignition
  68. Llist(points)=lfn0;
  69. end
  70. if(lfn0*lfn1<0),
  71. points=points+1;
  72. % coordinates of intersection of fire line with segment k k+1
  73. %lfn(t)=lfn0 + t*(lfn1-lfn0)=0
  74. t=lfn0/(lfn0-lfn1);
  75. x0=xx(k)+(xx(k+1)-xx(k))*t;
  76. y0=yy(k)+(yy(k+1)-yy(k))*t;
  77. xylist(points,:)=[x0,y0];
  78. Tlist(points)=0; % now at ignition
  79. Llist(points)=0; % at fireline
  80. end
  81. end
  82. % make the lists circular and trim to size
  83. Tlist(points+1)=Tlist(1);
  84. Tlist=Tlist(1:points+1);
  85. Llist(points+1)=Llist(1);
  86. Llist=Llist(1:points+1);
  87. xylist(points+1,:)=xylist(1,:);
  88. xylist=xylist(1:points+1,:);
  89. for k=1:5,lfnk(k)=lfn(ii(k),jj(k));end
  90. figure(1)
  91. plot3(xx,yy,lfnk,'k')
  92. hold on
  93. plot3(xylist(:,1),xylist(:,2),Tlist,'m--o')
  94. plot3(xylist(:,1),xylist(:,2),Llist,'g--o')
  95. plot(xx,yy,'b')
  96. plot(xylist(:,1),xylist(:,2),'-.r+')
  97. legend('lfn on whole cell','tign-tnow on burned area',...
  98. 'lfn on burned area', 'cell boundary','burned area boundary')
  99. patch(xylist(:,1),xylist(:,2),zeros(points+1,1),250,'FaceAlpha',0.3)
  100. patch(xylist(:,1),xylist(:,2),Tlist,100,'FaceAlpha',0.3)
  101. hold off,grid on,drawnow,pause(0.5)
  102. % set up least squares
  103. A=[xylist(1:points,1:2),ones(points,1)];
  104. v=Tlist(1:points);
  105. for i=1:points
  106. for j=1:points
  107. if(j~=i),
  108. dist(j)=norm(xylist(i,:)-xylist(j,:));
  109. else
  110. dist(j)=max(fd); % large
  111. end
  112. end
  113. rw(i)=1+min(dist); % weight = 1+min dist from other nodes
  114. end
  115. u = lscov(A,v,rw); % solve least squares to get coeffs of T
  116. residual=norm(A*u-v); % should be zero if T and L are linear
  117. nr=sqrt(u(1)*u(1)+u(2)*u(2));
  118. c=u(1)/nr;
  119. s=u(2)/nr;
  120. Q=[c, s; -s, c]; % rotation such that Q*u(1:2)=[something;0]
  121. ut=Q*u(1:2);
  122. errQ=ut(2); % should be zero
  123. ae=-ut(1)/fuel_time;
  124. ce=-u(3)/fuel_time; % -T(xt,yt)/fuel_time=ae*xt+ce
  125. xytlist=xylist*Q'; % rotate the points in the list
  126. xt=sort(xytlist(1:points,1)); % sort ascending in x
  127. fuel_fraction=0;
  128. for k=1:points-1
  129. % integrate the vertical slice from xt1 to xt2
  130. figure(2)
  131. plot(xytlist(:,1),xytlist(:,2),'-o'),grid on,hold on
  132. xt1=xt(k);
  133. xt2=xt(k+1);
  134. plot([xt1,xt1],sum(fd)*[-1,1]/3,'y')
  135. plot([xt2,xt2],sum(fd)*[-1,1]/3,'y')
  136. if(xt2-xt1>100*eps*max(fd)), % slice of nonzero width
  137. % find slice height as h=ah*x+ch
  138. upper=0;lower=0;
  139. ah=0;ch=0;
  140. for s=1:points % pass counterclockwise
  141. xts=xytlist(s,1); % start point of the line
  142. yts=xytlist(s,2);
  143. xte=xytlist(s+1,1); % end point of the line
  144. yte=xytlist(s+1,2);
  145. if (xts>xt1 & xte > xt1) | (xts<xt2 & xte < xt2)
  146. plot([xts,xte],[yts,yte],'--k')
  147. % that is not the one
  148. else % line y=a*x+c through (xts,yts), (xte,yte)
  149. a=(yts-yte)/(xts-xte);
  150. c=(xts*yte-xte*yts)/(xts-xte);
  151. if xte<xts % upper boundary
  152. aupp=a;
  153. cupp=c;
  154. plot([xts,xte],[yts,yte],'g')
  155. ah=ah+a;
  156. ch=ch+c;
  157. upper=upper+1;
  158. else % lower boundary
  159. alow=a;
  160. clow=c;
  161. plot([xts,xte],[yts,yte],'m')
  162. lower=lower+1;
  163. end
  164. end
  165. end
  166. if(lower~=1|upper~=1),
  167. error('slice does not have one upper and one lower line')
  168. end
  169. ah=aupp-alow;
  170. ch=cupp-clow;
  171. % debug only
  172. patch([xt1,xt2,xt2,xt1],...
  173. [alow*[xt1,xt2]+clow,aupp*[xt2,xt1]+cupp,],k*10)
  174. axis equal,drawnow, pause(0.5)
  175. figure(3)
  176. x=[xt1:(xt2-xt1)/100:xt2];
  177. plot(x,1-exp(ae*x+ce),x,ah*x+ch,x,...
  178. (ah*x+ch).*(1-exp(ae*x+ce)),[xt1,xt2],[0,0],'+k')
  179. xlabel x,legend('burned frac','slice height','height*burned','dividers')
  180. hold on,grid on,drawnow,pause(0.5)
  181. % integrate (ah*x+ch)*(1-exp(ae*x+ce) from xt1 to xt2
  182. % numerically sound for ae->0, ae -> infty
  183. % this can be important for different model scales
  184. % esp. if someone runs the model in single precision!!
  185. % s1=int((ah*x+ch),x,xt1,xt2)
  186. s1=(xt2-xt1)*((1/2)*ah*(xt2+xt1)+ch);
  187. % s2=int((ch)*(-exp(ae*x+ce)),x,xt1,xt2)
  188. ceae=ce/ae;
  189. s2=-ch*exp(ae*(xt1+ceae))*(xt2-xt1)*intexp(ae*(xt2-xt1));
  190. % s3=int((ah*x)*(-exp(ae*x+ce)),x,xt1,xt2)
  191. % s3=int((ah*x)*(-exp(ae*(x+ceae))),x,xt1,xt2)
  192. % expand in Taylor series around ae=0
  193. % collect(expand(taylor(int(x*(-exp(ae*(x+ceae))),x,xt1,xt2)*ae^2,ae,4)/ae^2),ae)
  194. % =(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
  195. % + (-1/3*xt2^3-1/2*xt2^2*ceae+1/3*xt1^3+1/2*xt1^2*ceae)*ae
  196. % + 1/2*xt1^2-1/2*xt2^2
  197. %
  198. % coefficient at ae^2 in the expansion, after some algebra
  199. 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));
  200. d=ae^4*a2;
  201. if abs(d)>eps
  202. % since ae*xt1+ce<=0 ae*xt2+ce<=0 all fine for large ae
  203. % for ae, ce -> 0 rounding error approx eps/ae^2
  204. s3=(exp(ae*(xt1+ceae))*(ae*xt1-1)-exp(ae*(xt2+ceae))*(ae*xt2-1))/ae^2;
  205. % we do not worry about rounding as xt1 -> xt2, then s3 -> 0
  206. else
  207. % coefficient at ae^1 in the expansion
  208. a1=(xt1-xt2)*((1/2)*ceae*(xt1+xt2)+(1/3)*(xt1^2+xt1*xt2+xt2^2));
  209. % coefficient at ae^0 in the expansion for ae->0
  210. a0=(1/2)*(xt1-xt2)*(xt1+xt2);
  211. s3=a0+a1*ae+a2*ae^2; % approximate the integral
  212. end
  213. s3=ah*s3;
  214. fuel_fraction=fuel_fraction+s1+s2+s3;
  215. if(fuel_fraction<0 | fuel_fraction>(fd(1)*fd(2))),
  216. fuel_fraction,(fd(1)*fd(2)),s1,s2,s3
  217. warning('fuel_fraction should be between 0 and 1')
  218. end
  219. end
  220. end
  221. fuel_fraction=fuel_fraction/(fd(1)*fd(2));
  222. end
  223. for i=figs,figure(i),hold off,end
  224. end % function
  225. function s=intexp(ab)
  226. % function s=intexp(ab)
  227. % s = (1/b)*int(exp(a*x),x,0,b) ab = a*b
  228. % = 1 if a==0
  229. if eps < abs(ab)^3/6,
  230. s = (exp(ab)-1)/(ab); % rounding error approx eps/(a*b) for small a*b
  231. else
  232. s = 1 + ab/2+ab^2/6; % last term (a*b)^2/6 for small a*b
  233. end
  234. end