bool CSimulateVariableWind::AssignParameters(){ int x,y; m_pDEM = Parameters("DEM")->asGrid(); m_pFuelGrid = Parameters("FUEL")->asGrid(); m_iWindDirGrids = Parameters("WINDDIR")->asInt(); m_pWindDirGrids =(CSG_Grid **)Parameters("WINDDIR")->asPointer(); m_iWindSpdGrids = Parameters("WINDSPD")->asInt(); m_pWindSpdGrids =(CSG_Grid **)Parameters("WINDSPD")->asPointer(); m_pM1Grid = Parameters("M1H")->asGrid(); m_pM10Grid = Parameters("M10H")->asGrid(); m_pM100Grid = Parameters("M100H")->asGrid(); m_pMHerbGrid = Parameters("MHERB")->asGrid(); m_pMWoodGrid = Parameters("MWOOD")->asGrid(); m_pTimeGrid = Parameters("TIME")->asGrid(); m_pFlameGrid = Parameters("FLAME")->asGrid(); m_pIntensityGrid = Parameters("INTENSITY")->asGrid(); m_fTimeLimit = Parameters("SIMULATIONTIME")->asInt(); m_fIgnTime = Parameters("IGNTIME")->asDouble(); m_fInterval = Parameters("INTERVAL")->asDouble(); m_fWorldX = Parameters("COORDX")->asDouble(); m_fWorldY = Parameters("COORDY")->asDouble(); m_iGridX = (int) ((m_fWorldX - m_pDEM->Get_XMin()) / m_pDEM->Get_Cellsize()); m_iGridY = (int) ((m_fWorldY - m_pDEM->Get_YMin()) / m_pDEM->Get_Cellsize()); m_Catalog = Fire_FuelCatalogCreateStandard("Standard", 13); Fire_FlameLengthTable(m_Catalog, 500, 0.1); if (!m_iWindDirGrids){ m_pWindDirGrids = new CSG_Grid*[1]; m_pWindDirGrids[0] = SG_Create_Grid(m_pDEM); m_pWindDirGrids[0]->Assign(Parameters("DEFAULTWINDDIR")->asDouble()); m_bDeleteWindDirGrid = true; }//if else{ m_bDeleteWindDirGrid = false; }//else if (!m_iWindSpdGrids){ m_pWindSpdGrids = new CSG_Grid*[1]; m_pWindSpdGrids[0] = SG_Create_Grid(m_pDEM); m_pWindSpdGrids[0]->Assign(Parameters("DEFAULTWINDSPD")->asDouble()); m_bDeleteWindSpdGrid = true; }//if else{ m_bDeleteWindSpdGrid = false; }//else //substitute no-data values for(y=0; y<Get_NY() && Set_Progress(y); y++){ for(x=0; x<Get_NX(); x++){ /*if (m_pWindSpdGrid->is_NoData(x, y)){ m_pWindSpdGrid->Set_Value(x, y, 0.); }//if if (m_pWindDirGrid->is_NoData(x, y)){ m_pWindDirGrid->Set_Value(x, y, 0.); }//if*/ if (m_pM1Grid->is_NoData(x, y)){ m_pM1Grid->Set_Value(x, y, 0.); }//if if (m_pM10Grid->is_NoData(x, y)){ m_pM10Grid->Set_Value(x, y, 0.); }//if if (m_pM100Grid->is_NoData(x, y)){ m_pM100Grid->Set_Value(x, y, 0.); }//if if (m_pMHerbGrid->is_NoData(x, y)){ m_pMHerbGrid->Set_Value(x, y, 0.); }//if if (m_pMWoodGrid->is_NoData(x, y)){ m_pMWoodGrid->Set_Value(x, y, 0.); }//if }//for }//for m_pReactionIntensityGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Double); m_pEffectiveWindGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Double); m_pHeatPerUnitAreaGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Double); //----------------------------------------------------- m_pSlopeGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Float); m_pAspectGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Float); for(y=0; y<Get_NY() && Set_Progress(y); y++) { for(x=0; x<Get_NX(); x++) { double Slope, Aspect; if( m_pDEM->Get_Gradient(x, y, Slope, Aspect) ) { m_pSlopeGrid ->Set_Value(x, y, Slope); m_pAspectGrid->Set_Value(x, y, Aspect); } else { m_pSlopeGrid ->Set_NoData(x, y); m_pAspectGrid->Set_NoData(x, y); } } } //----------------------------------------------------- m_pTimeGrid->Assign((double)0); return true; }//method
bool CSimulate::AssignParameters(){ int x,y; m_pDEM = Parameters("DEM")->asGrid(); m_pFuelGrid = Parameters("FUEL")->asGrid(); m_pIgnGrid = Parameters("IGNITION")->asGrid(); m_pWindDirGrid = Parameters("WINDDIR")->asGrid(); m_pWindSpdGrid = Parameters("WINDSPD")->asGrid(); m_pM1Grid = Parameters("M1H")->asGrid(); m_pM10Grid = Parameters("M10H")->asGrid(); m_pM100Grid = Parameters("M100H")->asGrid(); m_pMHerbGrid = Parameters("MHERB")->asGrid(); m_pMWoodGrid = Parameters("MWOOD")->asGrid(); m_pTimeGrid = Parameters("TIME")->asGrid(); m_pFlameGrid = Parameters("FLAME")->asGrid(); m_pIntensityGrid = Parameters("INTENSITY")->asGrid(); m_Catalog = Fire_FuelCatalogCreateStandard("Standard", 13); Fire_FlameLengthTable(m_Catalog, 500, 0.1); //substitute no-data values for(y=0; y<Get_NY() && Set_Progress(y); y++){ for(x=0; x<Get_NX(); x++){ if (m_pWindSpdGrid->is_NoData(x, y)){ m_pWindSpdGrid->Set_Value(x, y, 0.); }//if if (m_pWindDirGrid->is_NoData(x, y)){ m_pWindDirGrid->Set_Value(x, y, 0.); }//if if (m_pM1Grid->is_NoData(x, y)){ m_pM1Grid->Set_Value(x, y, 0.); }//if if (m_pM10Grid->is_NoData(x, y)){ m_pM10Grid->Set_Value(x, y, 0.); }//if if (m_pM100Grid->is_NoData(x, y)){ m_pM100Grid->Set_Value(x, y, 0.); }//if if (m_pMHerbGrid->is_NoData(x, y)){ m_pMHerbGrid->Set_Value(x, y, 0.); }//if if (m_pMWoodGrid->is_NoData(x, y)){ m_pMWoodGrid->Set_Value(x, y, 0.); }//if }//for }//for //----------------------------------------------------- // calculate slope and aspect using CSG_Grid class' // built-in function (after Zevenbergen & Thorne)... m_pSlopeGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Double); m_pAspectGrid = SG_Create_Grid(m_pDEM, SG_DATATYPE_Double); for(y=0; y<Get_NY() && Set_Progress(y); y++) { for(x=0; x<Get_NX(); x++) { double slope, aspect; if( m_pDEM->Get_Gradient(x, y, slope, aspect) ) { m_pSlopeGrid ->Set_Value(x, y, slope); m_pAspectGrid ->Set_Value(x, y, aspect); } else { m_pSlopeGrid ->Set_NoData(x, y); m_pAspectGrid ->Set_NoData(x, y); } } } //----------------------------------------------------- m_pTimeGrid->Assign((double)0); return true; }//method
int main ( int argc, char *argv[] ) { Rows = atoi(argv[1]); Cols = atoi(argv[1]); CellWd = 3.2808399*3000/Cols; /* Cell width (E-W) in feet. */ //1 m = 3.2808 ft CellHt = 3.2808399*3000/Cols; /* Cell height (N-S) in feet. */ //1 m = 3.2808 ft /* NOTE 2: Change these to set uniform burning conditions. */ size_t Model = 1; /* NFFL 1 */ double WindSpd = atof(argv[2]); /* m/s */ double WindDir = atof(argv[3]); /* degrees clockwise from north */ double M1 = atof(argv[4]); /* 1-hr dead fuel moisture */ double M10 = 0; /* 10-hr dead fuel moisture */ double M100 = 0; /* 100-hr dead fuel moisture */ double Mherb = 0; /* Live herbaceous fuel moisture */ double Mwood = 0; /* Live woody fuel moisture */ double slp_tmp, asp_tmp; //slope and aspect temporary values char buffer[100]; //buffer when usedm fgets skips lines /* neighbor's address*/ //N NE E SE S SW W NW a b c d e f g h static int nCol[16] = { 0, 1, 1, 1, 0, -1, -1, -1, -1, 1, -2, 2, -2, 2, -1, 1}; static int nRow[16] = { -1, -1, 0, 1, 1, 1, 0, -1, -2, -2, -1, -1, 1, 1, 2, 2}; static int nTimes = 0; /* counter for number of time steps */ FuelCatalogPtr catalog; /* fuel catalog handle */ double nDist[16]; /* distance to each neighbor */ double nAzm[16]; /* compass azimuth to each neighbor (0=N) */ double timeNow; /* current time (minutes) */ double timeNext; /* time of next cell ignition (minutes) */ int row, col, cell; /* row, col, and index of current cell */ int nrow, ncol, ncell; /* row, col, and index of neighbor cell */ int n, cells; /* neighbor index, total number of map cells */ size_t modelNumber; /* fuel model number at current cell */ double moisture[6]; /* fuel moisture content at current cell */ double fpm; /* spread rate in direction of neighbor */ double minutes; /* time to spread from cell to neighbor */ double ignTime; /* time neighbor is ignited by current cell */ int atEdge; /* flag indicating fire has reached edge */ size_t *fuelMap; /* ptr to fuel model map */ double *ignMap; /* ptr to ignition time map (minutes) */ double *flMap; /* ptr to flame length map (feet) */ double *slpMap; /* ptr to slope map (rise/reach) */ double *aspMap; /* ptr to aspect map (degrees from north) */ double *wspdMap; /* ptr to wind speed map (ft/min) */ double *wdirMap; /* ptr to wind direction map (deg from north) */ double *m1Map; /* ptr to 1-hr dead fuel moisture map */ double *m10Map; /* ptr to 10-hr dead fuel moisture map */ double *m100Map; /* ptr to 100-hr dead fuel moisture map */ double *mherbMap; /* ptr to live herbaceous fuel moisture map */ double *mwoodMap; /* ptr to live stem fuel moisture map */ FILE *slope_file, *aspect_file; printf("Running fireSim with Rows:%d, U:%lf, Dir:%lf\n", Rows, WindSpd, WindDir); /* NOTE 3: allocate all the maps. */ cells = Rows * Cols; if ( (ignMap = (double *) calloc(cells, sizeof(double))) == NULL || (flMap = (double *) calloc(cells, sizeof(double))) == NULL || (slpMap = (double *) calloc(cells, sizeof(double))) == NULL || (aspMap = (double *) calloc(cells, sizeof(double))) == NULL || (wspdMap = (double *) calloc(cells, sizeof(double))) == NULL || (wdirMap = (double *) calloc(cells, sizeof(double))) == NULL || (m1Map = (double *) calloc(cells, sizeof(double))) == NULL || (m10Map = (double *) calloc(cells, sizeof(double))) == NULL || (m100Map = (double *) calloc(cells, sizeof(double))) == NULL || (mherbMap = (double *) calloc(cells, sizeof(double))) == NULL || (mwoodMap = (double *) calloc(cells, sizeof(double))) == NULL || (fuelMap = (size_t *) calloc(cells, sizeof(size_t))) == NULL ) { fprintf(stderr, "Unable to allocate maps with %d cols and %d rows.\n", Cols, Rows); return (1); } /* NOTE 4: initialize all the maps -- modify them as you please. */ if ( (slope_file = fopen(argv[5],"r")) == NULL ){ printf("Unable to open output map \"%s\".\n", argv[5]); return (FIRE_STATUS_ERROR); } if ( (aspect_file = fopen(argv[6],"r")) == NULL ){ printf("Unable to open output map \"%s\".\n", argv[6]); return (FIRE_STATUS_ERROR); } /*for (n = 0; n < 6; n++){ fgets(buffer, 100, slope_file); fgets(buffer, 100, aspect_file); } */ for ( cell=0; cell<cells; cell++ ) { fscanf(aspect_file, "%lf", &asp_tmp); fscanf(slope_file, "%lf", &slp_tmp); slpMap[cell] = slp_tmp/100; //Slope in firelib is a fraction asp_tmp = (asp_tmp - 90 < 0) ? //while in Grass is percentage rise/reach. asp_tmp - 90 + 360 : asp_tmp - 90 ; //Aspect in firelib is N=0 and clockwise aspMap[cell] = 360 - asp_tmp; //while aspect in Grass is E=0 counter-clockwise fuelMap[cell] = Model; wspdMap[cell] = 196.850393701 * WindSpd; /* convert m/s into ft/min */ wdirMap[cell] = WindDir; m1Map[cell] = M1; m10Map[cell] = M10; m100Map[cell] = M100; mherbMap[cell] = Mherb; mwoodMap[cell] = Mwood; ignMap[cell] = INFINITY; flMap[cell] = 0.; } /* NOTE 5: set an ignition time & pattern (this ignites the middle cell). */ cell = floor(Cols/2) + Cols*floor(Rows/2); ignMap[cell] = 0.0; /* NOTE 6: create a standard fuel model catalog and a flame length table. */ //////////////////////////////// //Create fuel catalog //Create 13 + 0 (no fuel model) standard NFFL models and creates space for //aditional custom model catalog = Fire_FuelCatalogCreateStandard("Standard", 14); //Create aditional custom model based on NFFL1 //Only the PARTICLE LOAD is customized at the moment if ( Fire_FuelModelCreate ( catalog, //FuelCatalogData instance 14, //fuel model number "CUSTOM", //Name "Custom Fuel model", //longer description 0.197, //bed depth (ft) Fuel_Mext(catalog, 1), //moisture of extinction (dl) Fuel_SpreadAdjustment(catalog, 1), //spread adjustment factor (dl) 1) != FIRE_STATUS_OK ) //maximum number of particles { fprintf(stderr, "%s\n", FuelCat_Error(catalog)); Fire_FuelCatalogDestroy(catalog); return (NULL); } //Add a particle to the custom model nº 14 if ( Fire_FuelParticleAdd ( catalog, // FuelCatalogData instance pointer 14, //Custom fuel model id Fuel_Type(catalog,1,0), 0.23, // Custom particle load (lbs/ft2) 3500, // surface-area-to-volume ratio (ft2/ft3) Fuel_Density(catalog,1,0), //density (lbs/ft3) Fuel_Heat(catalog,1,0), //heat of combustion (btus/lb) Fuel_SiTotal(catalog,1,0), //total silica content (lb/lb) Fuel_SiEffective(catalog,1,0)) //effective silica content (lb/lb) != FIRE_STATUS_OK ) { fprintf(stderr, "%s\n", FuelCat_Error(catalog)); Fire_FuelCatalogDestroy(catalog); return (NULL); } Fire_FlameLengthTable(catalog, 500, 0.1); /* Calculate distance across cell to each neighbor and its azimuth. */ for ( n=0; n < 16; n++ ) { nDist[n] = sqrt ( nCol[n] * CellWd * nCol[n] * CellWd + nRow[n] * CellHt * nRow[n] * CellHt ); if (n < 8) nAzm[n] = n * 45.; else { nAzm[n] = atanf( (nCol[n] * CellWd) / (nRow[n] * CellHt) ); if ( nCol[n] > 0 && nRow[n] < 0) //1st quadrant nAzm[n] = RadToDeg( fabs( nAzm[n] ) ); if ( nCol[n] > 0 && nRow[n] > 0) //2st quadrant nAzm[n] = 180. - RadToDeg( nAzm[n] ) ; if ( nCol[n] < 0 && nRow[n] > 0) //3st quadrant nAzm[n] = RadToDeg( fabs( nAzm[n] ) )+ 180.; if ( nCol[n] < 0 && nRow[n] < 0) //4st quadrant nAzm[n] = 360. - RadToDeg( fabs( nAzm[n] )); } } /* NOTE 7: find the earliest (starting) ignition time. */ for ( timeNext=INFINITY, cell=0; cell<cells; cell++ ) { if ( ignMap[cell] < timeNext ) timeNext = ignMap[cell]; } /* NOTE 8: loop until no more cells can ignite or fire reaches an edge. */ atEdge = 0; //while ( timeNext < INFINITY && ! atEdge ) while ( timeNext < INFINITY) { timeNow = timeNext; timeNext = INFINITY; nTimes++; /* NOTE 9: examine each ignited cell in the fuel array. */ for ( cell=0, row=0; row<Rows; row++ ) { for ( col=0; col<Cols; col++, cell++ ) { /* Skip this cell if it has not ignited. */ if ( ignMap[cell] > timeNow ) { /* NOTE 12: first check if it is the next cell to ignite. */ if ( ignMap[cell] < timeNext ) timeNext = ignMap[cell]; continue; } /* NOTE 10: flag if the fire has reached the array edge. */ if ( row==0 || row==Rows-1 || col==0 || col==Cols-1 ) atEdge = 1; /* NOTE 11: determine basic fire behavior within this cell. */ modelNumber = fuelMap[cell]; moisture[0] = m1Map[cell]; moisture[1] = m10Map[cell]; moisture[2] = m100Map[cell]; moisture[3] = m100Map[cell]; moisture[4] = mherbMap[cell]; moisture[5] = mwoodMap[cell]; Fire_SpreadNoWindNoSlope(catalog, modelNumber, moisture); Fire_SpreadWindSlopeMax(catalog, modelNumber, wspdMap[cell], wdirMap[cell], slpMap[cell], aspMap[cell]); /* NOTE 12: examine each unignited neighbor. */ for ( n=0; n<16; n++ ) { /* First find the neighbor's location. */ nrow = row + nRow[n]; ncol = col + nCol[n]; if ( nrow<0 || nrow>=Rows || ncol<0 || ncol>=Cols ) continue; ncell = ncol + nrow*Cols; /* Skip this neighbor if it is already ignited. */ if ( ignMap[ncell] <= timeNow ) continue; /* Determine time to spread to this neighbor. */ Fire_SpreadAtAzimuth(catalog, modelNumber, nAzm[n], FIRE_NONE); if ( (fpm = Fuel_SpreadAny(catalog, modelNumber)) > Smidgen) { minutes = nDist[n] / fpm; /* Assign neighbor the earliest ignition time. */ if ( (ignTime = timeNow + minutes) < ignMap[ncell] ) { ignMap[ncell] = ignTime; Fire_FlameScorch(catalog, modelNumber, FIRE_FLAME); flMap[ncell] = Fuel_FlameLength(catalog,modelNumber); } /* Keep track of next cell ignition time. */ if ( ignTime < timeNext ) timeNext = ignTime; } } /* next neighbor n */ } /* next source col */ } /* next source row */ } /* next time */ printf("There were %d time steps ending at %3.2f minutes (%3.2f hours).\n", nTimes, timeNow, timeNow/60.); /* NOTE 13: save the ignition & flame length maps. */ PrintMap(aspMap,"aspect.Map"); PrintMap(slpMap,"slope.Map"); PrintMap(ignMap, "ign.Map"); PrintMap(flMap, "flame.Map"); return (0); }