00001
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027
00028 #include "HFire.h"
00029
00030
00031 #include "FireConfig.h"
00032 #include "FireProp.h"
00033
00034
00035 #include "CellState.h"
00036 #include "FireEnv.h"
00037 #include "FireExport.h"
00038 #include "FireTimer.h"
00039 #include "FireYear.h"
00040 #include "FuelsRegrowth.h"
00041 #include "StandAge.h"
00042 #include "Ignition.h"
00043 #include "Extinction.h"
00044 #include "EightNbr.h"
00045 #include "FuelModel.h"
00046 #include "Roth1972.h"
00047
00048
00049 #include "IntXY.h"
00050 #include "DblXYZ.h"
00051 #include "FltTwoDArray.h"
00052 #include "ByteTwoDArray.h"
00053 #include "GridData.h"
00054 #include "List.h"
00055 #include "ChHashTable.h"
00056 #include "NLIBRand.h"
00057 #include "Err.h"
00058
00059 void QuitFatal(char * emessage) {
00060 if ( emessage != NULL ) {
00061 fprintf(stderr, "%s", emessage);
00062 }
00063
00064 fprintf(stderr, "\n FATAL ERROR. Program Aborting.\n");
00065
00066 exit(1);
00067 }
00068
00069 void TimeStamp(FireTimer * ft, char * message) {
00070 int mt = 0;
00071
00072 if ( ft != NULL ) {
00073 mt = FIRE_TIMER_GET_MILITARY_TIME(ft);
00074 if ( message == NULL ) {
00075 fprintf(stdout, "SIM TIME... YR: %d MO: %02d DY: %02d HR: %04d SEC: %d \n", ft->sim_cur_yr,
00076 ft->sim_cur_mo, ft->sim_cur_dy, mt, ft->sim_cur_secs);
00077 }
00078 else {
00079 fprintf(stdout, "%s... YR: %d MO: %02d DY: %02d HR: %04d SEC: %d \n", message,
00080 ft->sim_cur_yr, ft->sim_cur_mo, ft->sim_cur_dy, mt, ft->sim_cur_secs);
00081 }
00082 }
00083 return;
00084 }
00085
00086 int main(int argc, char * argv[]) {
00087
00088
00089
00090
00091
00092
00093 ChHashTable * proptbl = NULL;
00094 GridData * elev = NULL;
00095 GridData * slope = NULL;
00096 GridData * aspect = NULL;
00097 GridData * std_age = NULL;
00098 GridData * fuels = NULL;
00099 FireTimer * ft = NULL;
00100 FireEnv * fe = NULL;
00101 List * fmlist = NULL;
00102 ChHashTable * fmtble = NULL;
00103 FireExport * fex = NULL;
00104
00105 int i, j;
00106
00107 int domain_rows, domain_cols;
00108
00109 float cellsz;
00110
00111 List * brn_cells_list = NULL;
00112
00113 ListElmt * lel = NULL;
00114
00115 double * rwx, * rwy;
00116
00117 IntXY * cell = NULL;
00118
00119 FuelModel * fm = NULL;
00120
00121 double cell_elev, nbr_elev;
00122
00123 double cell_slope;
00124
00125 double cell_aspect;
00126
00127 double d1hfm, d10hfm, d100hfm;
00128
00129 double lhfm, lwfm;
00130
00131 double cell_waz;
00132
00133 double cell_wsp;
00134
00135 int cell_fm_num;
00136
00137 int cell_az;
00138
00139 int num_brn_nbr;
00140
00141 int nbr_i, nbr_j;
00142
00143 int timestep, exp_secs, iter_secs;
00144
00145 FireYear * fyr = NULL;
00146
00147 CellState * cs = NULL;
00148
00149 ByteTwoDArray * hrs_brn = NULL;
00150
00151 FltTwoDArray * fract_brn = NULL;
00152
00153 FltTwoDArray * fract_iter = NULL;
00154
00155 double fpmros, mpsros;
00156
00157 double dist2ctr, disttrvl;
00158
00159 double fracttrvl, fractover;
00160
00161 KeyVal * entry = NULL;
00162
00163 void (*RandInit)(long int seed) = randinit;
00164
00165 char status_msg[HFIRE_DEFAULT_STATUS_LINE_LENGTH] = {'\0'};
00166
00167
00168 if ( argc != 2 ) {
00169 printf("Usage: %s <configuration filename> \n", argv[0]);
00170 return 0;
00171 }
00172
00173 if ( InitPropsFromFireConfig(&proptbl, argv[1]) ) {
00174 QuitFatal(NULL);
00175 }
00176 FireConfigDumpPropsToStream(proptbl, stdout);
00177
00178 if ( InitRothFuelModelListFromProps(proptbl, &fmlist) ) {
00179 QuitFatal(NULL);
00180 }
00181 FireConfigDumpFuelModelListToStream(fmlist, stdout);
00182
00183 if ( InitGridsFromPropsFireConfig(proptbl, &elev, &slope, &aspect)
00184 || InitFireTimerFromPropsFireConfig(proptbl, &ft)
00185 || InitFuelModelHashTableFromFuelModelListFireConfig(fmlist, &fmtble)
00186 || InitStandAgeFromPropsFireConfig(proptbl, elev, &std_age)
00187 || InitFireEnvFromPropsFireConfig(proptbl, &fe)
00188 || InitRandNumGenFromPropsFireConfig(proptbl, randinit) ) {
00189 QuitFatal(NULL);
00190 }
00191
00192 if ( (fex = InitFireExport(proptbl)) == NULL ) {
00193 QuitFatal(NULL);
00194 }
00195 FIRE_EXPORT_SET_FIRE_TIMER(fex, ft);
00196 FIRE_EXPORT_SET_STAND_AGE(fex, std_age);
00197
00198 if ( ChHashTableRetrieve(proptbl, GetFireProp(PROP_SIMTSSEC), (void *)&entry) ) {
00199 ERR_ERROR_CONTINUE("Unable to retrieve SIMULATION_TIMESTEP_SECS property.\n", ERR_EINVAL);
00200 QuitFatal(NULL);
00201 }
00202 timestep = atoi(entry->val);
00203
00204
00205
00206 while( !FireTimerIsSimTimeExpired(ft) ) {
00207
00208 ft->sim_cur_mo = ft->sim_start_mo;
00209 ft->sim_cur_dy = ft->sim_start_dy;
00210 ft->sim_cur_hr = ft->sim_start_hr;
00211
00212
00213 TimeStamp(ft, "START SIM YEAR");
00214
00215
00216
00217
00218 if ( fe->GetFuelsRegrowthFromProps(proptbl, std_age, &fuels) ) {
00219 QuitFatal(NULL);
00220 }
00221 FIRE_EXPORT_SET_FUELS(fex, fuels);
00222
00223
00224 domain_rows = fuels->ghdr->nrows;
00225 domain_cols = fuels->ghdr->ncols;
00226 cellsz = fuels->ghdr->cellsize;
00227
00228
00229 fyr = InitFireYearFuels(ft->sim_cur_yr, fuels, fmtble);
00230 FIRE_EXPORT_SET_FIRE_YEAR(fex, fyr);
00231
00232
00233 cs = InitCellStateFuels(fuels, fmtble);
00234
00235
00236 hrs_brn = InitByteTwoDArraySizeIniValue(domain_rows, domain_cols, 0);
00237
00238
00239 fract_brn = InitFltTwoDArraySizeIniValue(domain_rows, domain_cols, HFIRE_FRACT_ZERO);
00240
00241
00242 fract_iter = InitFltTwoDArraySizeIniValue(domain_rows, domain_cols, HFIRE_FRACT_ZERO);
00243
00244
00245 if ( fyr == NULL || cs == NULL || hrs_brn == NULL || fract_brn == NULL || fract_iter == NULL ) {
00246 QuitFatal(NULL);
00247 }
00248
00249
00250 while( !FireTimerIsSimCurYearTimeExpired(ft) ) {
00251
00252 if ( fe->IsIgnitionNowFromProps(proptbl) ) {
00253 if ( fe->GetIgnitionLocFromProps(proptbl, fyr, &brn_cells_list) ) {
00254 QuitFatal(NULL);
00255 }
00256 for( lel = LIST_HEAD(brn_cells_list); lel != NULL; lel = LIST_GET_NEXT_ELMT(lel) ) {
00257 rwx = LIST_GET_DATA(lel);
00258 lel = LIST_GET_NEXT_ELMT(lel);
00259 rwy = LIST_GET_DATA(lel);
00260 CellStateSetCellStateRealWorld(cs, *rwx, *rwy, EnumHasFireCellState);
00261 FireYearSetCellNewFireIDRealWorld(fyr, *rwx, *rwy);
00262 FireExportIgLocsTxtFile(proptbl, *rwx, *rwy, ft);
00263 }
00264 FreeList(brn_cells_list);
00265 }
00266
00267
00268 for(exp_secs = 0; exp_secs < timestep; exp_secs += iter_secs) {
00269
00270 iter_secs = timestep + 1;
00271
00272
00273 brn_cells_list = InitListEmpty(FreeIntXY);
00274
00275
00276 for(i = 0; i < domain_rows; i++) {
00277 for(j = 0; j < domain_cols; j++) {
00278
00279 FLTTWODARRAY_SET_DATA(fract_iter, i, j, HFIRE_FRACT_ZERO);
00280
00281 if ( BYTETWODARRAY_GET_DATA(cs->state, i, j) == EnumHasFireCellState ) {
00282
00283 if ( i == 0 || j == 0 || i == (domain_rows - 1) || j == (domain_cols - 1) ) {
00284 continue;
00285 }
00286
00287 GRID_DATA_GET_DATA(slope, i, j, cell_slope);
00288 GRID_DATA_GET_DATA(aspect, i, j, cell_aspect);
00289 GRID_DATA_GET_DATA(fuels, i, j, cell_fm_num);
00290
00291 if ( ChHashTableRetrieve(fmtble, &cell_fm_num, (void *)&fm) ) {
00292 QuitFatal(NULL);
00293 }
00294
00295 if ( IsSantaAnaNowFromProps(proptbl, ft->sim_cur_yr, ft->sim_cur_mo, ft->sim_cur_dy) ) {
00296 if ( GetSantaAnaEnvFromProps(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr,
00297 &cell_waz, UNITS_FT_TO_M(fm->rfm->fdepth), &cell_wsp, &d1hfm, &d10hfm, &d100hfm) ) {
00298 QuitFatal(NULL);
00299 }
00300 cell_wsp = UNITS_MPSEC_TO_FTPMIN(cell_wsp);
00301 }
00302
00303 else {
00304 if ( fe->GetDeadFuelMoistFromProps(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr,
00305 i, j, &d1hfm, &d10hfm, &d100hfm) ) {
00306 QuitFatal(NULL);
00307 }
00308 if ( fe->GetWindAzimuthFromProps(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr,
00309 i, j, &cell_waz) ) {
00310 QuitFatal(NULL);
00311 }
00312 if ( fe->GetWindSpeedMpsFromProps(proptbl, UNITS_FT_TO_M(fm->rfm->fdepth),
00313 ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr, i, j, &cell_wsp) ) {
00314 QuitFatal(NULL);
00315 }
00316 cell_wsp = UNITS_MPSEC_TO_FTPMIN(cell_wsp);
00317 }
00318
00319 if ( fe->GetLiveFuelMoistFromProps(proptbl, ft->sim_cur_yr, ft->sim_cur_mo, ft->sim_cur_dy,
00320 i, j, &lhfm, &lwfm) ) {
00321 QuitFatal(NULL);
00322 }
00323
00324 if ( Roth1972FireSpreadNoWindNoSlope(fm->rfm, d1hfm, d10hfm, d100hfm, lhfm, lwfm)
00325 || Roth1972FireSpreadWindSlopeMax(fm->rfm, cell_wsp, cell_waz, cell_slope, cell_aspect) ) {
00326 QuitFatal(NULL);
00327 }
00328 fpmros = fm->rfm->rp->ros_max;
00329 mpsros = UNITS_FTPMIN_TO_MPSEC(fpmros);
00330
00331 if ( (cellsz / mpsros) < iter_secs ) {
00332 iter_secs = cellsz / mpsros;
00333 }
00334
00335 lel = LIST_TAIL(brn_cells_list);
00336 ListInsertNext(brn_cells_list, lel, InitIntXY(j,i));
00337 }
00338 }
00339 }
00340
00341
00342 if ( LIST_SIZE(brn_cells_list) > 0 ) {
00343
00344 if ( iter_secs < 1 ) {
00345 iter_secs = 1;
00346 }
00347
00348 if ( iter_secs + exp_secs > timestep ) {
00349 iter_secs = timestep - exp_secs;
00350 }
00351 }
00352 else {
00353
00354 TimeStamp(ft, "NO CELLS BURNING");
00355 FreeList(brn_cells_list);
00356 break;
00357 }
00358
00359
00360 for( lel = LIST_HEAD(brn_cells_list); lel != NULL; lel = LIST_GET_NEXT_ELMT(lel) ) {
00361 cell = LIST_GET_DATA(lel);
00362 i = cell->y;
00363 j = cell->x;
00364
00365 GRID_DATA_GET_DATA(elev, i, j, cell_elev);
00366 GRID_DATA_GET_DATA(slope, i, j, cell_slope);
00367 GRID_DATA_GET_DATA(aspect, i, j, cell_aspect);
00368 GRID_DATA_GET_DATA(fuels, i, j, cell_fm_num);
00369
00370 if ( ChHashTableRetrieve(fmtble, &cell_fm_num, (void *)&fm) ) {
00371 QuitFatal(NULL);
00372 }
00373
00374 if ( IsSantaAnaNowFromProps(proptbl, ft->sim_cur_yr, ft->sim_cur_mo, ft->sim_cur_dy) ) {
00375 if ( GetSantaAnaEnvFromProps(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr,
00376 &cell_waz, UNITS_FT_TO_M(fm->rfm->fdepth), &cell_wsp, &d1hfm, &d10hfm, &d100hfm) ) {
00377 QuitFatal(NULL);
00378 }
00379 cell_wsp = UNITS_MPSEC_TO_FTPMIN(cell_wsp);
00380 }
00381
00382 else {
00383 if ( fe->GetDeadFuelMoistFromProps(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr,
00384 i, j, &d1hfm, &d10hfm, &d100hfm) ) {
00385 QuitFatal(NULL);
00386 }
00387 if ( fe->GetWindAzimuthFromProps(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr,
00388 i, j, &cell_waz) ) {
00389 QuitFatal(NULL);
00390 }
00391 if ( fe->GetWindSpeedMpsFromProps(proptbl, UNITS_FT_TO_M(fm->rfm->fdepth),
00392 ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr, i, j, &cell_wsp) ) {
00393 QuitFatal(NULL);
00394 }
00395 cell_wsp = UNITS_MPSEC_TO_FTPMIN(cell_wsp);
00396 }
00397
00398 if ( fe->GetLiveFuelMoistFromProps(proptbl, ft->sim_cur_yr, ft->sim_cur_mo, ft->sim_cur_dy,
00399 i, j, &lhfm, &lwfm) ) {
00400 QuitFatal(NULL);
00401 }
00402
00403 num_brn_nbr = 0;
00404
00405 if ( Roth1972FireSpreadNoWindNoSlope(fm->rfm, d1hfm, d10hfm, d100hfm, lhfm, lwfm)
00406 || Roth1972FireSpreadWindSlopeMax(fm->rfm, cell_wsp, cell_waz, cell_slope, cell_aspect) ) {
00407 QuitFatal(NULL);
00408 }
00409 fpmros = fm->rfm->rp->ros_max;
00410 mpsros = UNITS_FTPMIN_TO_MPSEC(fpmros);
00411
00412 if ( UpdateExtinctionROS(proptbl, i, j, mpsros, cs, hrs_brn) ) {
00413
00414 FLTTWODARRAY_SET_DATA(fract_brn, i, j, HFIRE_FRACT_ZERO);
00415 FLTTWODARRAY_SET_DATA(fract_iter, i, j, HFIRE_FRACT_ZERO);
00416 continue;
00417 }
00418
00419 for (cell_az = 0; cell_az < EIGHTNBR_NUM_NBR_CELLS; cell_az++) {
00420 nbr_i = EIGHTNBR_ROW_INDEX_AT_AZIMUTH(i, cell_az);
00421 nbr_j = EIGHTNBR_COL_INDEX_AT_AZIMUTH(j, cell_az);
00422
00423 if ( nbr_i == 0 || nbr_j == 0 || nbr_i == (domain_rows - 1) || nbr_j == (domain_cols - 1) ) {
00424 num_brn_nbr++;
00425 continue;
00426 }
00427
00428 if ( BYTETWODARRAY_GET_DATA(cs->state, nbr_i, nbr_j) != EnumNoFireCellState ) {
00429 num_brn_nbr++;
00430 continue;
00431 }
00432
00433 if ( Roth1972FireSpreadGetAtAzimuth(fm->rfm, EIGHTNBR_AZIMUTH_AS_DBL(cell_az)) ) {
00434 QuitFatal(NULL);
00435 }
00436 fpmros = fm->rfm->rp->ros_any;
00437 mpsros = UNITS_FTPMIN_TO_MPSEC(fpmros);
00438
00439 disttrvl = mpsros * iter_secs;
00440
00441 GRID_DATA_GET_DATA(elev, nbr_i, nbr_j, nbr_elev);
00442 if ( dxyzCalcDist(j * cellsz, i * cellsz, cell_elev,
00443 nbr_j * cellsz, nbr_i * cellsz, nbr_elev, &dist2ctr) ) {
00444 QuitFatal(NULL);
00445 }
00446
00447 fracttrvl = disttrvl / dist2ctr;
00448
00449 if ( FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) <= HFIRE_FRACT_ZERO ) {
00450 FLTTWODARRAY_SET_DATA(fract_brn, nbr_i, nbr_j, fracttrvl);
00451 }
00452
00453 else if ( fracttrvl > FLTTWODARRAY_GET_DATA(fract_iter, nbr_i, nbr_j) ) {
00454
00455 FLTTWODARRAY_SET_DATA(fract_brn, nbr_i, nbr_j, (FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) - FLTTWODARRAY_GET_DATA(fract_iter, nbr_i, nbr_j)));
00456
00457 FLTTWODARRAY_SET_DATA(fract_brn, nbr_i, nbr_j, (FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) + fracttrvl));
00458 FLTTWODARRAY_SET_DATA(fract_iter, nbr_i, nbr_j, fracttrvl);
00459 }
00460
00461 else {
00462 continue;
00463 }
00464
00465 fractover = FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) - 1.0;
00466 if ( fractover > 1.0 ) {
00467
00468 BYTETWODARRAY_SET_DATA(cs->state, nbr_i, nbr_j, EnumHasFireCellState);
00469
00470 num_brn_nbr++;
00471
00472 INTTWODARRAY_SET_DATA(fyr->id, nbr_i, nbr_j, INTTWODARRAY_GET_DATA(fyr->id, i, j));
00473
00474 nbr_i = EIGHTNBR_ROW_INDEX_AT_AZIMUTH(nbr_i, cell_az);
00475 nbr_j = EIGHTNBR_COL_INDEX_AT_AZIMUTH(nbr_j, cell_az);
00476 if ( BYTETWODARRAY_GET_DATA(cs->state, nbr_i, nbr_j) == EnumNoFireCellState ) {
00477 if ( FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) <= HFIRE_FRACT_ZERO ) {
00478 FLTTWODARRAY_SET_DATA(fract_brn, nbr_i, nbr_j, fractover);
00479 }
00480 else if ( fractover > FLTTWODARRAY_GET_DATA(fract_iter, nbr_i, nbr_j) ) {
00481
00482 FLTTWODARRAY_SET_DATA(fract_brn, nbr_i, nbr_j, (FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) - FLTTWODARRAY_GET_DATA(fract_iter, nbr_i, nbr_j)));
00483
00484 FLTTWODARRAY_SET_DATA(fract_brn, nbr_i, nbr_j, (FLTTWODARRAY_GET_DATA(fract_brn, nbr_i, nbr_j) + fractover));
00485 FLTTWODARRAY_SET_DATA(fract_iter, nbr_i, nbr_j, fractover);
00486 }
00487 }
00488 }
00489 }
00490
00491 if ( num_brn_nbr >= EIGHTNBR_NUM_NBR_CELLS ) {
00492 BYTETWODARRAY_SET_DATA(cs->state, i, j, EnumConsumedCellState);
00493 }
00494 }
00495
00496
00497 FreeList(brn_cells_list);
00498 sprintf(status_msg, "T_exp: %d T_adapt: %d", exp_secs, iter_secs);
00499 TimeStamp(ft, status_msg);
00500 }
00501
00502
00503 FireTimerIncrementSeconds(ft, timestep);
00504
00505
00506 if ( UpdateExtinctionHOURS(proptbl, ft->sim_cur_mo, ft->sim_cur_dy, ft->sim_cur_hr, cs, hrs_brn) ) {
00507 QuitFatal(NULL);
00508 }
00509
00510
00511 if ( FireExportSpatialData(proptbl, fex) ) {
00512 QuitFatal(NULL);
00513 }
00514
00515
00516 TimeStamp(ft, NULL);
00517
00518
00519 }
00520
00521
00522 if ( FireExportSpatialData(proptbl, fex) ) {
00523 QuitFatal(NULL);
00524 }
00525
00526
00527 IncrementStandAge(fyr, std_age);
00528
00529
00530 FreeGridData(fuels);
00531 FreeFireYear(fyr);
00532 FreeCellState(cs);
00533 FreeByteTwoDArray(hrs_brn);
00534 FreeFltTwoDArray(fract_brn);
00535 FreeFltTwoDArray(fract_iter);
00536
00537
00538 TimeStamp(ft, "END SIM YEAR");
00539
00540
00541 ft->sim_cur_yr += 1;
00542
00543
00544 }
00545
00546
00547 FreeFireExport(fex);
00548 FreeFireEnv(fe);
00549 FreeGridData(std_age);
00550 FreeChHashTable(fmtble);
00551 FreeFireTimer(ft);
00552 FreeGridData(aspect);
00553 FreeGridData(slope);
00554 FreeGridData(elev);
00555 FreeList(fmlist);
00556 FreeChHashTable(proptbl);
00557 return 0;
00558 }
00559
00560