Statistics
| Revision:

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
}