root / org.gvsig.toolbox / trunk / org.gvsig.toolbox / org.gvsig.toolbox.algorithm / src / main / java / wf / rothermel / Behave.java @ 59
History | View | Annotate | Download (26.4 KB)
1 |
/**
|
---|---|
2 |
* A modified version of the Behave class by Andreas Bachmann,
|
3 |
* available at http://www.geo.unizh.ch/gis/research/edmg/fire/unc.html
|
4 |
*
|
5 |
* @author: Andreas Bachman, Victor Olaya
|
6 |
*
|
7 |
*
|
8 |
*/
|
9 |
package wf.rothermel; |
10 |
|
11 |
public class Behave { |
12 |
|
13 |
|
14 |
/**
|
15 |
* INSTANCE VARS
|
16 |
*/
|
17 |
|
18 |
public boolean isCalculated = false; |
19 |
public boolean canDerive = true; |
20 |
|
21 |
// Rothermel's model input variables
|
22 |
public int fuelModel = 0; // fuel model nr |
23 |
public double w0_d1 = 0.; // Fuel loading [kg/m2] |
24 |
public double w0_d2 = 0.; |
25 |
public double w0_d3 = 0.; |
26 |
public double w0_lh = 0.; |
27 |
public double w0_lw = 0.; |
28 |
public double sv_d1 = 0.; // surface to volume ratio [1/m] |
29 |
public double sv_d2 = 357.6115; |
30 |
public double sv_d3 = 98.4252; |
31 |
public double sv_lh = 4921.2598; |
32 |
public double sv_lw = 4921.2598; |
33 |
public double depth = 0.; // fuel bed depth [m] |
34 |
public double rho_p = 512.72341; // particle density [kg/m3] |
35 |
public double heat = 18606.70194; // particle low heat content [kJ/kg] |
36 |
public double s_t = 5.5; // total mineral content [%] |
37 |
public double s_e = 1.0; // effective mineral content [%] |
38 |
public double mx = 0.; // moisture of extinction, dead fuel [%] |
39 |
public double m_d1 = 0.; // fuel moisture [%] |
40 |
public double m_d2 = 0.; |
41 |
public double m_d3 = 0.; |
42 |
public double m_lh = 0.; |
43 |
public double m_lw = 0.; |
44 |
|
45 |
public double wsp = 0.; // wind speed [m/s] |
46 |
public double wdr = 0.; // wind dir [Degree],Northern wind = 0.0! |
47 |
public double slp = 0.; // slope [Degree] |
48 |
public double asp = 0.; // aspect [Degree] southfacing = 180 ! |
49 |
|
50 |
// additional variables...
|
51 |
public double rho_b = 0.; // bulk density [kg/m3] |
52 |
public double beta = 0.; // packing ratio |
53 |
public double beta_opt = 0.; // optimal packing ratio |
54 |
public double beta_ratio = 0.; // ratio mean/optimal packing ratio |
55 |
public double w_n = 0.; // net fuel loading |
56 |
public double eta_s = 0.; // mineral damping coefficient |
57 |
public double eta_M = 0.; // moisture damping coefficient |
58 |
public double xi = 0.; // propagating flux ratio |
59 |
public double A = 0.; |
60 |
public double gamma = 0.; // potential reaction velocity [1/s] |
61 |
public double gamma_max = 0.; // maximum reaction velocity [1/s] |
62 |
public double I_r = 0.; // reaction intensity [kW/m2] |
63 |
public double phi_s = 0.; // slope factor |
64 |
public double B, C, E = 0.; |
65 |
public double phi_w = 0.; // wind factor |
66 |
public double phi_t = 0.; // combined slope/wind factor |
67 |
public double vx, vy, vl = 0.; // Vector components |
68 |
public double ecc = 0; // eccentricity |
69 |
|
70 |
public double asp_r; // radians equivalent of asp |
71 |
public double slp_r; // radians equivalent of slp |
72 |
public double wdr_r; // radians equivalent of wdr |
73 |
public double sdr_r; // radians equivalent of sdr |
74 |
public double sin_asp; |
75 |
public double cos_asp; |
76 |
public double sin_wdr; |
77 |
public double cos_wdr; |
78 |
public double tan_slp; |
79 |
|
80 |
public double al; |
81 |
public double splitDeg, splitRad; |
82 |
public double cos_splitRad, sin_splitRad; |
83 |
public double alDeg, alRad; |
84 |
|
85 |
public double sw_d1, sw_d2, sw_d3, sw_lh, sw_lw, sw_d, sw_l, sw_t = 0.; |
86 |
public double s2w_d, s2w_l, s2w_t = 0.; |
87 |
public double sw2_d, sw2_l, sw2_t = 0.; |
88 |
public double swm_d, swm_l, swm_t = 0.; |
89 |
public double sigma = 0.; |
90 |
public double w0 = 0.; |
91 |
public double wn_d1, wn_d2, wn_d3, wn_lh, wn_lw, wn_d, wn_l; |
92 |
|
93 |
public double eps_d1, eps_d2, eps_d3, eps_lh, eps_lw; |
94 |
public double q_d1, q_d2, q_d3, q_lh, q_lw; |
95 |
public double hskz; |
96 |
|
97 |
public double hn_d1, hn_d2, hn_d3, hn_lh, hn_lw = 0.; |
98 |
public double sumhd, sumhl, sumhdm = 0.; |
99 |
public double W = 0.; // W' ratio of "fine" fuel loading |
100 |
public double eta_Ml, eta_Md = 0.; // damping coefficient |
101 |
public double rm_d, rm_l = 0.; // moisture ratio |
102 |
public double Mf_dead = 0.; // Moisture content of dead fine fuel |
103 |
public double Mx_live = 0.; // Moisture of extinction of living fuel |
104 |
public double dead, live = 0.; |
105 |
|
106 |
// resulting variables
|
107 |
public double sdr = 0.; // spread direction [degree] |
108 |
public double efw = 0.; // effective wind speed [m/s] |
109 |
public double hsk = 0.; // heat sink term [kJ/m3] |
110 |
public double ros = 0.; // rate of spread [m/s] |
111 |
public double tau = 0.; // flame residence time [s] |
112 |
public double hpa = 0.; // heat release per unit area [kJ/m2] |
113 |
public double fzd = 0.; // flame zone depth [m] |
114 |
public double fli = 0.; // fire line intensity [kW/m] |
115 |
public double fln = 0.; // flame length [m] |
116 |
|
117 |
|
118 |
public boolean setFuelModel(final int model) { |
119 |
|
120 |
if (model != this.fuelModel) { |
121 |
this.fuelModel = model;
|
122 |
switch (fuelModel) {
|
123 |
case 1: |
124 |
setFuelModelValues(0.18, 0., 0., 0., 0., 0.3048, 11482.940, 12.); |
125 |
break;
|
126 |
case 2: |
127 |
setFuelModelValues(0.486, 0.243, 0.122, 0.122, 0., 0.3048, 9842.0, 15.); |
128 |
break;
|
129 |
case 3: |
130 |
setFuelModelValues(0.732, 0., 0., 0., 0., 0.762, 4921.2598, 25); |
131 |
break;
|
132 |
case 4: |
133 |
setFuelModelValues(1.218, 0.975, 0.486, 1.218, 0., 1.8288, 6561.67979, 20); |
134 |
break;
|
135 |
case 5: |
136 |
setFuelModelValues(0.243, 0.122, 0., 0., 0.122, 0.6096, 6561.680, 20); |
137 |
break;
|
138 |
case 6: |
139 |
setFuelModelValues(0.365, 0.608, 0., 0., 0.486, 0.732, 5741.47, 25); |
140 |
break;
|
141 |
case 7: |
142 |
setFuelModelValues(0.275, 0.645, 0.365, 0., 0.090, 0.762, 5741.47, 40); |
143 |
break;
|
144 |
/*case 8:
|
145 |
setFuelmodelValues(0.365, 0.243, 0.6075, 0.0, 0.06096, *, 30);
|
146 |
break;
|
147 |
case 9:
|
148 |
setFuelmodelValues(0.7046, 0.0996, 0.03645, 0.0, 0.06096, *, 25);
|
149 |
break;
|
150 |
case 10:
|
151 |
setFuelmodelValues(0.729, 0.486, 1.215, 0.486, 0.3048, * 25);
|
152 |
break;
|
153 |
case 11:
|
154 |
setFuelmodelValues(0.365, 1.093, 1.3365, 0.0, 0.3048, *, 15);
|
155 |
break;
|
156 |
case 12:
|
157 |
setFuelmodelValues(0.972, 3.402, 4.0095, 0.0, 0.6992,*, 20);
|
158 |
break;
|
159 |
case 13:
|
160 |
setFuelmodelValues(1.701, 5.589, 6.804, 0.0, 0.9144,*, 25);
|
161 |
break;*/
|
162 |
default:
|
163 |
return false; |
164 |
} |
165 |
} |
166 |
else if (model < 1 || model > 13) { |
167 |
return false; |
168 |
} |
169 |
|
170 |
return true; |
171 |
|
172 |
} |
173 |
|
174 |
|
175 |
private void setFuelModelValues(final double wd1, |
176 |
final double wd2, |
177 |
final double wd3, |
178 |
final double wlh, |
179 |
final double wlw, |
180 |
final double dep, |
181 |
final double sv, |
182 |
final double mox) { |
183 |
|
184 |
w0_d1 = wd1; |
185 |
w0_d2 = wd2; |
186 |
w0_d3 = wd3; |
187 |
w0_lh = wlh; |
188 |
w0_lw = wlw; |
189 |
depth = dep; |
190 |
sv_d1 = sv; |
191 |
mx = mox; |
192 |
w0 = w0_d1 + w0_d2 + w0_d3 + w0_lh + w0_lw; |
193 |
|
194 |
} |
195 |
|
196 |
|
197 |
public void setWindSpeed(final double speed) { |
198 |
this.wsp = speed;
|
199 |
} |
200 |
|
201 |
|
202 |
public void setWindDir(final double dir) { |
203 |
this.wdr = dir;
|
204 |
} |
205 |
|
206 |
|
207 |
public void setSlope(final double slope) { |
208 |
this.slp = slope;
|
209 |
} |
210 |
|
211 |
|
212 |
public void setAspect(final double aspect) { |
213 |
this.asp = aspect;
|
214 |
} |
215 |
|
216 |
|
217 |
public void setDeadMoisture1(final double moisture) { |
218 |
this.m_d1 = moisture;
|
219 |
} |
220 |
|
221 |
|
222 |
public void setDeadMoisture10(final double moisture) { |
223 |
this.m_d2 = moisture;
|
224 |
} |
225 |
|
226 |
|
227 |
public void setDeadMoisture100(final double moisture) { |
228 |
this.m_d3 = moisture;
|
229 |
} |
230 |
|
231 |
|
232 |
public void setHerbMoisture(final double moisture) { |
233 |
this.m_lh = moisture;
|
234 |
} |
235 |
|
236 |
|
237 |
public void setWoodyMoisture(final double moisture) { |
238 |
this.m_lw = moisture;
|
239 |
} |
240 |
|
241 |
|
242 |
public static double getRosInDir(final double dRos, |
243 |
final double dMaxDirection, |
244 |
final double dDirection, |
245 |
final double dEcc) { |
246 |
|
247 |
double dDir;
|
248 |
|
249 |
if ((dDir = Math.abs(dMaxDirection - dDirection)) > 180.) { |
250 |
dDir = 360. - dDir;
|
251 |
} |
252 |
|
253 |
return (dRos * (1. - dEcc) / (1. - dEcc * Math.cos(Math.toRadians(dDir)))); |
254 |
|
255 |
} |
256 |
|
257 |
|
258 |
public void calc() { |
259 |
calcRothermel(); |
260 |
} |
261 |
|
262 |
|
263 |
/******************************************************************************************************************************
|
264 |
* calcRothermel
|
265 |
*
|
266 |
* the main logic of rothermel wildfire behaviour calculation
|
267 |
*
|
268 |
*****************************************************************************************************************************/
|
269 |
private void calcRothermel() { |
270 |
|
271 |
// reset flags
|
272 |
isCalculated = false;
|
273 |
canDerive = true;
|
274 |
|
275 |
/* prepare fuel parameters */
|
276 |
calcFuel(); |
277 |
|
278 |
/* mineral damping coefficient: eta_s */
|
279 |
/* Rothermel 1972: eq. (62) */
|
280 |
eta_s = 0.174 * Math.pow(s_e / 100, -0.19); |
281 |
|
282 |
/* moisture damping coefficient: eta_M */
|
283 |
moistureDamping(); |
284 |
|
285 |
/* reaction velocity: gamma */
|
286 |
reactionVelocity(); |
287 |
|
288 |
/* reaction intensity */
|
289 |
I_r = gamma * heat * eta_s * eta_M; |
290 |
|
291 |
/* propagating flux ratio: xi
|
292 |
Rothermel 1972: eq. (42)
|
293 |
Formula:
|
294 |
with sigma[1/ft]:
|
295 |
xi = exp[(0.792 + 0.681* sqrt(sigma))*(beta + 0.1)] /
|
296 |
(192 + 0.259*sigma)
|
297 |
with sigma[1/m] :
|
298 |
xi = exp[(0.792 + 0.681*sqrt(.3048)*sqrt(sigma))*(beta + 0.1)] /
|
299 |
(192 + 0.259*0.3048*sigma)
|
300 |
*/
|
301 |
xi = Math.exp((0.792 + 0.37597 * Math.sqrt(sigma)) * (beta + 0.1)) / (192 + 0.0791 * sigma); |
302 |
|
303 |
/* heat sink: hsk */
|
304 |
heatSink(); |
305 |
|
306 |
/* forward rate of spread */
|
307 |
/* no wind and no slope */
|
308 |
ros = I_r * xi / hsk; |
309 |
|
310 |
/* wind and slope */
|
311 |
combinedWindAndSlopeFactor(); // -> phi_t
|
312 |
|
313 |
if (phi_t > 0.) { |
314 |
ros = I_r * xi * (1 + phi_t) / hsk; // (52), [m/s] |
315 |
} |
316 |
|
317 |
/** ******************************************************************** */
|
318 |
/* additional fire behaviour results */
|
319 |
//
|
320 |
/* flame residence time: tau */
|
321 |
/* Anderson 1969, in Albini (1976), p.91: */
|
322 |
/* tau = 384/ sigma [min] */
|
323 |
tau = 384. * 60 / (sigma * 0.3048); // [s] |
324 |
|
325 |
/* heat release per unit area: hpa */
|
326 |
hpa = I_r * tau; |
327 |
|
328 |
/* flame zone depth */
|
329 |
fzd = ros * tau; |
330 |
|
331 |
/* fireline intensity */
|
332 |
fli = I_r * fzd; |
333 |
|
334 |
/* flame length */
|
335 |
/* based on Byram (1959), in Albini (1976), p. 91 */
|
336 |
fln = 0.0775 * Math.pow(fli, 0.46); |
337 |
|
338 |
/* it's over...*/
|
339 |
isCalculated = true;
|
340 |
} |
341 |
|
342 |
|
343 |
/******************************************************************************************************************************
|
344 |
* calcFuel
|
345 |
*
|
346 |
* calculates: - characteristic surface-to-volume ration (sigma) - bulk densities (rho_b) - packing ratios (beta, beta_opt,
|
347 |
* beta_ratio) - net fuel loadings (wn_..)
|
348 |
*
|
349 |
*
|
350 |
* Exceptions are thrown if - w0 <= 0. no fuel specified - sw_t <= 0. surface-to-voume-ratios not properly specified - depth <=
|
351 |
* 0. depth of fuel bed not properly specified
|
352 |
*****************************************************************************************************************************/
|
353 |
protected void calcFuel() { |
354 |
|
355 |
/* reset all values to 0. ***************************/
|
356 |
sigma = 0.;
|
357 |
rho_b = 0.;
|
358 |
beta = 0.;
|
359 |
beta_opt = 0.;
|
360 |
beta_ratio = 0.;
|
361 |
// sw_
|
362 |
sw_d1 = 0.;
|
363 |
sw_d2 = 0.;
|
364 |
sw_d3 = 0.;
|
365 |
sw_lh = 0.;
|
366 |
sw_lw = 0.;
|
367 |
s2w_d = 0.;
|
368 |
s2w_l = 0.;
|
369 |
s2w_t = 0.;
|
370 |
sw2_d = 0.;
|
371 |
sw2_l = 0.;
|
372 |
sw2_t = 0.;
|
373 |
swm_d = 0.;
|
374 |
swm_l = 0.;
|
375 |
//
|
376 |
wn_d1 = 0.;
|
377 |
wn_d2 = 0.;
|
378 |
wn_d3 = 0.;
|
379 |
wn_lh = 0.;
|
380 |
wn_lw = 0.;
|
381 |
wn_d = 0.;
|
382 |
wn_l = 0.;
|
383 |
/** ********************************************** */
|
384 |
|
385 |
// auxiliary variables
|
386 |
sw_d1 = sv_d1 * w0_d1; |
387 |
sw_d2 = sv_d2 * w0_d2; |
388 |
sw_d3 = sv_d3 * w0_d3; |
389 |
sw_lh = sv_lh * w0_lh; |
390 |
sw_lw = sv_lw * w0_lw; |
391 |
sw_d = sw_d1 + sw_d2 + sw_d3; |
392 |
sw_l = sw_lh + sw_lw; |
393 |
sw_t = sw_d + sw_l; |
394 |
//
|
395 |
s2w_d = sw_d1 * sv_d1 + sw_d2 * sv_d2 + sw_d3 * sv_d3; |
396 |
s2w_l = sw_lh * sv_lh + sw_lw * sv_lw; |
397 |
s2w_t = s2w_d + s2w_l; |
398 |
//
|
399 |
sw2_d = sw_d1 * w0_d1 + sw_d2 * w0_d2 + sw_d3 * w0_d3; |
400 |
sw2_l = sw_lh * w0_lh + sw_lw * w0_lw; |
401 |
sw2_t = sw2_d + sw2_l; |
402 |
//
|
403 |
swm_d = sw_d1 * m_d1 + sw_d2 * m_d2 + sw_d3 * m_d3; |
404 |
swm_l = sw_lh * m_lh + sw_lw * m_lw; |
405 |
|
406 |
sigma = s2w_t / sw_t; |
407 |
|
408 |
/**
|
409 |
* mean bulk density Rothermel 1972: eq. (74)
|
410 |
*/
|
411 |
// see further down "beta"
|
412 |
// rho_b should not be bigger than 0.5 of the particle density
|
413 |
//
|
414 |
rho_b = w0 / depth; |
415 |
/**
|
416 |
* packing ratios
|
417 |
*/
|
418 |
// mean packing ratio
|
419 |
beta = rho_b / rho_p; |
420 |
// should be between 0. and 0.5?
|
421 |
// in Rothermel 1972, p.18-19, values are between 0 and 0.12
|
422 |
if ((beta > 1) || (beta < 0)) { |
423 |
System.out.println("Mean packing ration [beta] out of limits [0,1]: " + beta); |
424 |
} |
425 |
|
426 |
// optimal packing ratio
|
427 |
beta_opt = 8.8578 * Math.pow(sigma, -0.8189); |
428 |
|
429 |
// ratio mean / optimal packing
|
430 |
beta_ratio = beta / beta_opt; |
431 |
|
432 |
/**
|
433 |
* Net fuel loading Rothermel 1972: eq. (60), adjusted by Albini 1976, p.88
|
434 |
*/
|
435 |
wn_d1 = w0_d1 * (1 - s_t / 100); |
436 |
wn_d2 = w0_d2 * (1 - s_t / 100); |
437 |
wn_d3 = w0_d3 * (1 - s_t / 100); |
438 |
wn_lh = w0_lh * (1 - s_t / 100); |
439 |
wn_lw = w0_lw * (1 - s_t / 100); |
440 |
// Rothermel 1972: eq. (59)
|
441 |
if (sw_d > 0) { |
442 |
wn_d = (1 - s_t / 100) * sw2_d / sw_d; |
443 |
} |
444 |
if (sw_l > 0) { |
445 |
wn_l = (1 - s_t / 100) * sw2_l / sw_l; |
446 |
} |
447 |
} |
448 |
|
449 |
|
450 |
//END calcFuel()
|
451 |
|
452 |
/******************************************************************************************************************************
|
453 |
* phi_s: slope factor
|
454 |
*
|
455 |
* called from combinedWindAndSlopeFactor()
|
456 |
*****************************************************************************************************************************/
|
457 |
protected void slopeFactor() { |
458 |
slp_r = Math.toRadians(slp);
|
459 |
tan_slp = Math.tan(slp_r);
|
460 |
phi_s = 5.275 * Math.pow(beta, -0.3) * Math.pow(tan_slp, 2); |
461 |
} |
462 |
|
463 |
|
464 |
/******************************************************************************************************************************
|
465 |
* phi_w: wind factor
|
466 |
*
|
467 |
* called from combinedWindAndSlopeFactor()
|
468 |
*
|
469 |
* conversion: sigma [1/ft] = sigma[1/m] * 0.3048! original formulae in Rothermel 1972, eq. XXXXX B = 0.013298 *
|
470 |
* Math.pow(sigma,0.54); C = 7.47 * Math.exp(-0.06919 * Math.pow(sigma,0.55)); E = 0.715 * Math.exp(0.0001094 * sigma);
|
471 |
*
|
472 |
*****************************************************************************************************************************/
|
473 |
protected void windFactor() { |
474 |
B = 0.02526 * Math.pow(sigma * 0.3048, 0.54); |
475 |
C = 7.47 * Math.exp(-0.133 * Math.pow(sigma * 0.3048, 0.55)); |
476 |
E = 0.715 * Math.exp(-0.000359 * 0.3048 * sigma); |
477 |
phi_w = C * Math.pow(3.281 * 60 * wsp, B) * Math.pow(beta_ratio, -E); |
478 |
} |
479 |
|
480 |
|
481 |
/******************************************************************************************************************************
|
482 |
* phi combined wind and slope factor assumptions: wsp > 0. and/or slp > 0.
|
483 |
* -> phi_t
|
484 |
*****************************************************************************************************************************/
|
485 |
protected void combinedWindAndSlopeFactor() { |
486 |
// reset values
|
487 |
phi_t = 0.;
|
488 |
vl = 0.;
|
489 |
|
490 |
// calculate the wind and slope factor
|
491 |
slopeFactor(); // -> phi_s
|
492 |
windFactor(); // -> phi_w
|
493 |
|
494 |
// combine the two factors using a vector sum..
|
495 |
// conversion of input values....
|
496 |
asp_r = Math.toRadians(asp);
|
497 |
wdr_r = Math.toRadians(wdr);
|
498 |
|
499 |
// Flip Aspect
|
500 |
// -> upslope direction is needed
|
501 |
if (asp_r < Math.PI) { |
502 |
asp_r = asp_r + Math.PI;
|
503 |
} |
504 |
else {
|
505 |
asp_r = asp_r - Math.PI;
|
506 |
} |
507 |
|
508 |
/*
|
509 |
* Flip Wind Direction
|
510 |
* standard meteorological definitions says
|
511 |
* winddirection == direction where the wind is blowing FROM
|
512 |
* for the calculation we need
|
513 |
* winddirection == direction where the is blowing TO
|
514 |
*/
|
515 |
if (wdr_r < Math.PI) { |
516 |
wdr_r = wdr_r + Math.PI;
|
517 |
} |
518 |
else {
|
519 |
wdr_r = wdr_r - Math.PI;
|
520 |
} |
521 |
|
522 |
/* the following code according to fireLib.c
|
523 |
* 1. normalize for upslope direction
|
524 |
* 2. consider differing angle of wind by splitAngle
|
525 |
*/
|
526 |
splitRad = Math.abs(wdr_r - asp_r) >= Math.PI ? wdr_r + asp_r - 2 * Math.PI : wdr_r - asp_r; |
527 |
cos_splitRad = Math.cos(splitRad);
|
528 |
sin_splitRad = Math.sin(splitRad);
|
529 |
vx = phi_s + phi_w * cos_splitRad; |
530 |
vy = phi_w * sin_splitRad; |
531 |
vl = Math.sqrt(vx * vx + vy * vy);
|
532 |
//
|
533 |
al = Math.asin(vy / vl);
|
534 |
//
|
535 |
if (vx >= 0.) { |
536 |
alRad = (vy >= 0.) ? asp_r + al : asp_r + al + 2 * Math.PI; |
537 |
} |
538 |
else {
|
539 |
alRad = asp_r - al + Math.PI;
|
540 |
} |
541 |
alDeg = Math.toDegrees(alRad);
|
542 |
if (alDeg > 360) { |
543 |
alDeg -= 360.;
|
544 |
} |
545 |
//
|
546 |
sdr = alDeg; |
547 |
/***************************************************************************************************************************
|
548 |
* effective windspeed actually this is only the inverse function of phi_w
|
549 |
**************************************************************************************************************************/
|
550 |
efw = (Math.pow(vl / (C * Math.pow(beta_ratio, -E)), 1 / B)) / 196.85; |
551 |
// rothermel 87: sets an upper limit on
|
552 |
// the wind multiplication factor
|
553 |
if (efw > 0.024 * I_r) { |
554 |
efw = Math.min(efw, 0.024 * I_r); |
555 |
phi_t = C * Math.pow(196.85 * efw, B) * Math.pow(beta_ratio, -E); |
556 |
// flag that derivations are not allowed!
|
557 |
canDerive = false;
|
558 |
} |
559 |
else {
|
560 |
phi_t = vl; |
561 |
} |
562 |
final double lwRatio = 1. + 0.002840909 * efw; |
563 |
ecc = Math.sqrt(lwRatio * lwRatio - 1.0) / lwRatio; |
564 |
|
565 |
} |
566 |
|
567 |
|
568 |
/******************************************************************************************************************************
|
569 |
* moistureDamping ********************************************************************* calculate the moisture damping
|
570 |
* coefficients for dead and live fuel
|
571 |
*
|
572 |
* Exceptions thrown if mx <= 0.
|
573 |
*/
|
574 |
protected void moistureDamping() { |
575 |
// reset variables...
|
576 |
hn_d1 = 0.;
|
577 |
hn_d2 = 0.;
|
578 |
hn_d3 = 0.;
|
579 |
hn_lh = 0.;
|
580 |
hn_lw = 0.;
|
581 |
sumhd = 0.;
|
582 |
sumhl = 0.;
|
583 |
sumhdm = 0.;
|
584 |
W = 0.;
|
585 |
Mf_dead = 0.;
|
586 |
Mx_live = 0.;
|
587 |
eta_Ml = 0.;
|
588 |
eta_Md = 0.;
|
589 |
eta_M = 0.;
|
590 |
|
591 |
/**
|
592 |
* moisture damping coefficient weighting factors for live moisture of extinction...
|
593 |
*
|
594 |
* Rothermel (1972): eq. (88) (mx)_living = 2.9W(1-(M_f)_dead/0.3) - 0.226 (min = 0.3)
|
595 |
* => Albini (1976): page 89! (mx)_living = 2.9W'(1-(M'_f)_dead/(mx)_dead) - 0.226 (min = mx)
|
596 |
*
|
597 |
* -------------------------------------------------------- Ratio of "fine fuel loadings, dead/live W' =
|
598 |
* SUM(w0_d*exp(-138/sv_d*)/SUM(w0_l*exp(-500/sv_l*) 0.20482 = Multiplier for [pound/ft2] to [kg/m2] -452.76 = -138 / 0.3048
|
599 |
* -1640.2 = -500 / 0.3048
|
600 |
*/
|
601 |
if (sv_d1 > 0.) { |
602 |
hn_d1 = 0.20482 * w0_d1 * Math.exp(-452.76 / sv_d1); |
603 |
} |
604 |
if (sv_d2 > 0.) { |
605 |
hn_d2 = 0.20482 * w0_d2 * Math.exp(-452.76 / sv_d2); |
606 |
} |
607 |
if (sv_d3 > 0.) { |
608 |
hn_d3 = 0.20482 * w0_d3 * Math.exp(-452.76 / sv_d3); |
609 |
} |
610 |
if (sv_lh > 0.) { |
611 |
hn_lh = 0.20482 * w0_lh * Math.exp(-1640.42 / sv_lh); |
612 |
} |
613 |
if (sv_lw > 0.) { |
614 |
hn_lw = 0.20482 * w0_lw * Math.exp(-1640.42 / sv_lw); |
615 |
} |
616 |
|
617 |
// sum up...
|
618 |
sumhd = hn_d1 + hn_d2 + hn_d3; |
619 |
sumhl = hn_lh + hn_lw; |
620 |
sumhdm = hn_d1 * m_d1 + hn_d2 * m_d2 + hn_d3 * m_d3; |
621 |
|
622 |
/*
|
623 |
moisture damping for live fuel
|
624 |
*/
|
625 |
// calc only if there is any live fuel available...
|
626 |
// sw_l = sv_lh * w0_lh + sv_lw * w0_lw
|
627 |
// sw_l > 0 ensures that sumhl > 0
|
628 |
if (sw_l > 0.) { |
629 |
// W' ratio of "fine" fuel loading, dead/living
|
630 |
W = sumhd / sumhl; |
631 |
|
632 |
// Moisture content of "fine" dead fuel
|
633 |
if (sumhd > 0) { |
634 |
Mf_dead = sumhdm / sumhd; |
635 |
} |
636 |
|
637 |
// Moisture of extinction of living fuel
|
638 |
Mx_live = (2.9 * W * (1 - Mf_dead / mx) - 0.226) * 100; |
639 |
|
640 |
/*
|
641 |
* Check for Minimum of Mx_live
|
642 |
* Mx_live = Math.max(Mx_live,mx)
|
643 |
*
|
644 |
* if Mx_live is lower than mx, we have a problem with the
|
645 |
* calculation of the error, as the function is no longer continuos
|
646 |
*
|
647 |
*/
|
648 |
if (Mx_live < mx) {
|
649 |
canDerive = false;
|
650 |
Mx_live = mx; |
651 |
} |
652 |
// dead moisture ratio
|
653 |
rm_l = swm_l / (sw_l * Mx_live); |
654 |
} |
655 |
|
656 |
// moisture ratios
|
657 |
// Rothermel (1972): eq. (65) & (66)
|
658 |
if (sw_d > 0) { |
659 |
rm_d = swm_d / (sw_d * mx); |
660 |
} |
661 |
|
662 |
// moisture damping coefficient
|
663 |
// Rothermel (1972): eq. (64)
|
664 |
// damping coefficients range from 0 to 1 (Rothermel 1972, p.11!).
|
665 |
// 0 means a moisture ratio rm_* greater than 1, i.e. the moisture
|
666 |
// content is higher than the moisture of extinction
|
667 |
//
|
668 |
eta_Md = 1 - 2.59 * (rm_d) + 5.11 * Math.pow(rm_d, 2) - 3.52 * Math.pow(rm_d, 3); |
669 |
eta_Ml = 1 - 2.59 * (rm_l) + 5.11 * Math.pow(rm_l, 2) - 3.52 * Math.pow(rm_l, 3); |
670 |
|
671 |
// check for eta_* lower than 0;
|
672 |
if (eta_Md < 0) { |
673 |
eta_Md = 0.;
|
674 |
} |
675 |
if (eta_Ml < 0) { |
676 |
eta_Ml = 0.;
|
677 |
} |
678 |
|
679 |
//
|
680 |
eta_M = wn_d * eta_Md + wn_l * eta_Ml; |
681 |
} |
682 |
|
683 |
|
684 |
/******************************************************************************************************************************
|
685 |
* gamma': reaction velocity
|
686 |
*
|
687 |
*****************************************************************************************************************************/
|
688 |
protected void reactionVelocity() { |
689 |
/**
|
690 |
* exponent A: => Rothermel 1972 eq.(70), replaced by Albini (1976) (p.88) A = 133 * sigma**-0.7913 ;sigma[1/ft] = 133 *
|
691 |
* 0.3048**-0.7913 * sigma**-0.7913 ;sigma[1/m] = 340.53 * sigma**-0.7913 ;sigma[1/m]
|
692 |
*/
|
693 |
A = 340.53 * Math.pow(sigma, -0.7913); |
694 |
/**
|
695 |
* maximum reaction velocity: => Rothermel 1972: (68), based on (36) conversion: gamma_max [min-1] = 60 gamma_max [s-1]
|
696 |
* Formulae: gamma_max = sigma**1.5 / (495 + 0.0594* sigma**1.5) counter = sigma**1.5 ;sigma [1/ft] = 1 * Math.pow(0.3048,
|
697 |
* 1.5) * sigma**1.5 ;sigma [1/m] = 0.16828 * sigma**1.5
|
698 |
*
|
699 |
* denominator = 495 + 0.0594 * sigma**1.5 ;sigma[1/ft] = 495*60 + 0.0594*60*0.16828 * sigma**1.5 ;sigma[1/m] = 29700 +
|
700 |
* 0.5997 * sigma**1.5 ;sigma[1/m]
|
701 |
*/
|
702 |
gamma_max = 0.16828 * Math.pow(sigma, 1.5) / (29700 + 0.5997 * Math.pow(sigma, 1.5)); |
703 |
gamma = gamma_max * Math.pow(beta_ratio, A) * Math.exp(A * (1 - beta_ratio)); |
704 |
} |
705 |
|
706 |
|
707 |
/******************************************************************************************************************************
|
708 |
* heat sink term
|
709 |
*
|
710 |
* Rothermel (1972): eq. (77) + (78)
|
711 |
*****************************************************************************************************************************/
|
712 |
protected void heatSink() { |
713 |
/**
|
714 |
* Effective heating number: epsilon = exp(-138 / sigma_ft) (14) = exp(-138 / (sigma_m * 0.3048)) conversion! = exp( -452.76 /
|
715 |
* sigma)
|
716 |
*/
|
717 |
|
718 |
if (sv_d1 > 0.0) { |
719 |
eps_d1 = Math.exp(-452.76 / sv_d1); |
720 |
} |
721 |
if (sv_d2 > 0.0) { |
722 |
eps_d2 = Math.exp(-452.76 / sv_d2); |
723 |
} |
724 |
if (sv_d3 > 0.0) { |
725 |
eps_d3 = Math.exp(-452.76 / sv_d3); |
726 |
} |
727 |
if (sv_lh > 0.0) { |
728 |
eps_lh = Math.exp(-452.76 / sv_lh); |
729 |
} |
730 |
if (sv_lw > 0.0) { |
731 |
eps_lw = Math.exp(-452.76 / sv_lw); |
732 |
} |
733 |
/**
|
734 |
* Heat of Preignition: Q_ig, [Btu/lb] = 1.05506 kJ / 0.4535 kg = 2.3265 kJ/kg Q_ig = 250.0 + 1116 * M_f ; M_f [fraction] =
|
735 |
* 581.5 + 2.3265 *(0.01 * M_f) ; M_f [%]
|
736 |
*/
|
737 |
q_d1 = 581.5 + 25.957 * m_d1; |
738 |
q_d2 = 581.5 + 25.957 * m_d2; |
739 |
q_d3 = 581.5 + 25.957 * m_d3; |
740 |
q_lh = 581.5 + 25.957 * m_lh; |
741 |
q_lw = 581.5 + 25.957 * m_lw; |
742 |
|
743 |
/**
|
744 |
* Heat Sink
|
745 |
*/
|
746 |
hskz = sw_d1 * eps_d1 * q_d1 + sw_d2 * eps_d2 * q_d2 + sw_d3 * eps_d3 * q_d3 + sw_lh * eps_lh * q_lh + sw_lw * eps_lw |
747 |
* q_lw; |
748 |
hsk = rho_b * hskz / sw_t; |
749 |
} |
750 |
|
751 |
} |