int CSimulateVariableWind::CalculateFireSpreading(double fTimeLimit){

	int x,y;
	int x2,y2;
	int i,j;
	bool bReturn = false;
	/* neighbor's address*/   /* N  NE   E  SE   S  SW   W  NW */
	static int nX[8] =        {  0,  1,  1,  1,  0, -1, -1, -1};
    static int nY[8] =        {  1,  1,  0, -1, -1, -1,  0,  1};
	double fDist;			  /* distance to neighbor */
    double fAz;				  /* compass azimuth to neighbor (0=N) */	
	size_t modelNumber;       /* fuel model number at current cell */
    double moisture[6];       /* fuel moisture content at current cell */
    double dSpreadRate;       /* spread rate in direction of neighbor */
    double dSpreadTime;       /* time to spread from cell to neighbor */
    double dIgnTime;          /* time neighbor is ignited by current cell */
	double dWindSpd;
	double dWindDir;
	int iBurntCells = 0;

	while (m_CentralPoints.Get_Count()!=0){

		for (int iPt=0; iPt<m_CentralPoints.Get_Count();iPt++){

			x = m_CentralPoints.Get_X(iPt);
			y = m_CentralPoints.Get_Y(iPt);

			if (!m_pDEM->is_NoData(x,y) && !m_pFuelGrid->is_NoData(x,y)){

				modelNumber = (size_t) m_pFuelGrid->asInt(x, y);
				moisture[0] = m_pM1Grid->asDouble(x, y) / 100.;
				moisture[1] = m_pM10Grid->asDouble(x, y) / 100.;
				moisture[2] = m_pM100Grid->asDouble(x, y) / 100.;
				moisture[3] = m_pM100Grid->asDouble(x, y) / 100.;
				moisture[4] = m_pMHerbGrid->asDouble(x, y) / 100.;
				moisture[5] = m_pMWoodGrid->asDouble(x, y) / 100.;
				dWindSpd = getWindSpeed(x, y, m_pTimeGrid->asDouble(x,y)) * KMH2FTMIN; 
				dWindDir = 360. - getWindDirection(x, y, m_pTimeGrid->asDouble(x,y));
				Fire_SpreadNoWindNoSlope(m_Catalog, modelNumber, moisture);
				Fire_SpreadWindSlopeMax(m_Catalog, modelNumber, dWindSpd,
										 dWindDir, tan(m_pSlopeGrid->asDouble(x,y)),
										 m_pAspectGrid->asDouble(x,y));

				for (i = -2; i < 3 ; i++){
					for (j = -2; j < 3; j++){						
						if (i!= 0 || j!=0){					
							x2 = x + i;
							y2 = y + j;
							if (m_pTimeGrid->is_InGrid(x2,y2,false)){
								fAz = getAzimuth(i,j);
								Fire_SpreadAtAzimuth(m_Catalog, modelNumber, fAz, FIRE_BYRAMS);
								dSpreadRate = Fuel_SpreadAny(m_Catalog, modelNumber); // in ft/min (awkward...)					
								dSpreadRate *= FTMIN2MMIN; //a bit better...
								if (dSpreadRate > Smidgen){
									fDist = sqrt(pow(i,2.) + pow(j,2.)) * m_pTimeGrid->Get_Cellsize();
									dSpreadTime = fDist / dSpreadRate;							
									dIgnTime = 	m_pTimeGrid->asDouble(x,y) + dSpreadTime;
									if (dIgnTime < fTimeLimit){
										if (m_pTimeGrid->asDouble(x2,y2) == 0.0 
												|| m_pTimeGrid->asDouble(x2, y2)>dIgnTime){
											m_pTimeGrid->Set_Value(x2, y2, dIgnTime);
											m_AdjPoints.Add(x2,y2);
											Fire_FlameScorch(m_Catalog, modelNumber, FIRE_FLAME);
											m_pFlameGrid->Set_Value(x2, y2, Fuel_FlameLength(m_Catalog, modelNumber) * FT2M);									
											m_pIntensityGrid->Set_Value(x2, y2, Fuel_ByramsIntensity(m_Catalog, modelNumber)
																		* BTU2KCAL / FT2M );
											m_pReactionIntensityGrid->Set_Value(x2, y2, Fuel_RxIntensity(m_Catalog, modelNumber));
											m_pHeatPerUnitAreaGrid->Set_Value(x2, y2, Fuel_HeatPerUnitArea(m_Catalog, modelNumber));
											m_pEffectiveWindGrid->Set_Value(x2,y2, Fuel_EffectiveWind(m_Catalog, modelNumber));
										}//if
									}//if
								}//if					
							}//if
						}//if				
					}//for
				}//for

			}//if
		}//for

		m_CentralPoints.Clear();
		for (int i=0; i<m_AdjPoints.Get_Count(); i++){
			x= m_AdjPoints.Get_X(i);
			y = m_AdjPoints.Get_Y(i);
			m_CentralPoints.Add(x, y);
			iBurntCells++;
		}//for
		m_AdjPoints.Clear();

		if (fTimeLimit == NO_TIME_LIMIT){
			Process_Get_Okay(true);
		}//if		

	}//while

	return iBurntCells;

}//method
int CSimulate::CalculateFireSpreading(float fTimeLimit){

	int x,y;
	int x2,y2;
	int n;
	bool bReturn = false;
	/* neighbor's address*/   /* N  NE   E  SE   S  SW   W  NW */
	static int nX[8] =        {  0,  1,  1,  1,  0, -1, -1, -1};
    static int nY[8] =        {  1,  1,  0, -1, -1, -1,  0,  1};
	double nDist[8];          /* distance to each neighbor */
    double nAzm[8];           /* compass azimuth to each neighbor (0=N) */	
	size_t modelNumber;       /* fuel model number at current cell */
    double moisture[6];       /* fuel moisture content at current cell */
    double dSpreadRate;       /* spread rate in direction of neighbor */
    double dSpreadTime;       /* time to spread from cell to neighbor */
    double dIgnTime;          /* time neighbor is ignited by current cell */
	double dWindSpd;
	int iBurntCells = 0;

	bool bUpdate = Parameters("UPDATEVIEW")->asBool();

    for (n=0; n<8; n++){
        nDist[n] = sqrt ( nX[n] * m_pDEM->Get_Cellsize() * nX[n] * m_pDEM->Get_Cellsize()
                        + nY[n] * m_pDEM->Get_Cellsize() * nY[n] * m_pDEM->Get_Cellsize() );
        nAzm[n] = n * 45.;
    }//for

	while (m_CentralPoints.Get_Count()!=0){

		for (int iPt=0; iPt<m_CentralPoints.Get_Count();iPt++){

			x = m_CentralPoints.Get_X(iPt);
			y = m_CentralPoints.Get_Y(iPt);

			if (!m_pDEM->is_NoData(x,y) && !m_pFuelGrid->is_NoData(x,y)){

				modelNumber = (size_t) m_pFuelGrid->asInt(x, y);
				moisture[0] = m_pM1Grid->asFloat(x, y);
				moisture[1] = m_pM10Grid->asFloat(x, y);
				moisture[2] = m_pM100Grid->asFloat(x, y);
				moisture[3] = m_pM100Grid->asFloat(x, y);
				moisture[4] = m_pMHerbGrid->asFloat(x, y);;
				moisture[5] = m_pMWoodGrid->asFloat(x, y);
				dWindSpd = m_pWindSpdGrid->asFloat(x,y)  * MS2FTMIN; 
				Fire_SpreadNoWindNoSlope(m_Catalog, modelNumber, moisture);
				Fire_SpreadWindSlopeMax(m_Catalog, modelNumber, dWindSpd,
										 m_pWindDirGrid->asFloat(x,y), tan(m_pSlopeGrid->asFloat(x,y)),
										 m_pAspectGrid->asFloat(x,y));

				for (n=0; n<8; n++){
					x2 = x + nX[n];
					y2 = y + nY[n];
					if (m_pTimeGrid->is_InGrid(x2,y2,false)){
						Fire_SpreadAtAzimuth(m_Catalog, modelNumber, nAzm[n], FIRE_BYRAMS);
						dSpreadRate = Fuel_SpreadAny(m_Catalog, modelNumber); // in ft/min (awkward...)					
						dSpreadRate *= FTMIN2MMIN; //a bit better...
						if (dSpreadRate > Smidgen){
							dSpreadTime = nDist[n] / dSpreadRate;							
							if (fTimeLimit == NO_TIME_LIMIT){
								dIgnTime = 	m_pTimeGrid->asDouble(x,y) + dSpreadTime;
								if (m_pTimeGrid->asDouble(x2,y2) == 0.0 
										|| m_pTimeGrid->asDouble(x2, y2) > dIgnTime + THRESHOLD_FOR_DIFFERENCE ){
									m_pTimeGrid->Set_Value(x2, y2, dIgnTime);
									m_AdjPoints.Add(x2,y2);
									Fire_FlameScorch(m_Catalog, modelNumber, FIRE_FLAME);
									m_pFlameGrid->Set_Value(x2, y2, Fuel_FlameLength(m_Catalog, modelNumber) * FT2M);									
									m_pIntensityGrid->Set_Value(x2, y2, Fuel_ByramsIntensity(m_Catalog, modelNumber)
																* BTU2KCAL / FT2M );									
								}//if
							}//if
						}//if					
					}//if
				}//for
			}//if
		}//for

		m_CentralPoints.Clear();
		for (int i=0; i<m_AdjPoints.Get_Count(); i++){
			x= m_AdjPoints.Get_X(i);
			y = m_AdjPoints.Get_Y(i);
			m_CentralPoints.Add(x, y);
		}//for
		m_AdjPoints.Clear();

		if (fTimeLimit == NO_TIME_LIMIT){
			Process_Get_Okay(true);
		}//if	
		
		if (bUpdate){
			DataObject_Update(m_pTimeGrid, true);
		}

	}//while

	return iBurntCells;

}//method
Beispiel #3
0
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);
}