From 2e1928822d22a1915addb85d60eeea941e99e757 Mon Sep 17 00:00:00 2001 From: Thoreau Romain Date: Mon, 9 Sep 2024 13:55:28 +0200 Subject: [PATCH 1/2] add NN option for propagation model --- configs/nn_rothermel_andrews_uniform.yaml | 20 +++++++++++++ configs/rothermel_andrews_uniform.yaml | 7 +++-- configs/rothermel_uniform.yaml | 1 + .../forefire_helper.cpython-38.pyc | Bin 37756 -> 37793 bytes test/forefire_helper.py | 3 ++ test/simulation.py | 3 ++ test/tf_to_bin.py | 28 ++++++++++-------- test/uniform_simulation.py | 4 +-- 8 files changed, 48 insertions(+), 18 deletions(-) create mode 100644 configs/nn_rothermel_andrews_uniform.yaml diff --git a/configs/nn_rothermel_andrews_uniform.yaml b/configs/nn_rothermel_andrews_uniform.yaml new file mode 100644 index 0000000..0b66112 --- /dev/null +++ b/configs/nn_rothermel_andrews_uniform.yaml @@ -0,0 +1,20 @@ +propagation_model: ANNPropagationModel +nn_ros_model_path: /home/ai4geo/Documents/nn_ros_models/nn_abs_256_RothermelAndrews2018/saved_model.ffann +fuel_type: 6 +domain_width: 2000 +domain_height: 2000 +horizontal_wind: 20.0 +vertical_wind: 0.0 +slope: 0 +nb_steps: 10 +step_size: 10 +fire_front: [[950, 1050], [1000, 1000], [950, 950]] + +spatial_increment: 0.5 +perimeter_resolution: 2 # max distance between two nodes +minimal_propagative_front_depth: 5 # resolution of arrival time matrix +min_speed: 0.0 +max_speed: 20.0 +relax: 1 # takes 0.2 of the new ROS and 0.8 of the old ROS, to set in function of spatial_increment! +propagation_speed_adjustment_factor: 1 +burned_map_layer: diff --git a/configs/rothermel_andrews_uniform.yaml b/configs/rothermel_andrews_uniform.yaml index 493120c..a5b42c5 100644 --- a/configs/rothermel_andrews_uniform.yaml +++ b/configs/rothermel_andrews_uniform.yaml @@ -1,8 +1,9 @@ propagation_model: RothermelAndrews2018 +nn_ros_model_path: fuel_type: 6 domain_width: 2000 domain_height: 2000 -horizontal_wind: 20.0 +horizontal_wind: 200.0 vertical_wind: 0.0 slope: 0 nb_steps: 10 @@ -13,7 +14,7 @@ spatial_increment: 0.5 perimeter_resolution: 2 # max distance between two nodes minimal_propagative_front_depth: 5 # resolution of arrival time matrix min_speed: 0.0 -max_speed: 20.0 -relax: 0.2 # takes 0.2 of the new ROS and 0.8 of the old ROS, to set in function of spatial_increment! +max_speed: 100.0 +relax: 1 # takes 0.2 of the new ROS and 0.8 of the old ROS, to set in function of spatial_increment! propagation_speed_adjustment_factor: 1 burned_map_layer: diff --git a/configs/rothermel_uniform.yaml b/configs/rothermel_uniform.yaml index d23b6f7..beff34d 100644 --- a/configs/rothermel_uniform.yaml +++ b/configs/rothermel_uniform.yaml @@ -1,4 +1,5 @@ propagation_model: Rothermel +nn_ros_model_path: fuel_type: 141 domain_width: 2000 domain_height: 2000 diff --git a/test/__pycache__/forefire_helper.cpython-38.pyc b/test/__pycache__/forefire_helper.cpython-38.pyc index b238b67c6a814b62d7e628261cc7df31d4e6e3b2..02728f24cd251f446b0cae5f7fa2f9e3725960e0 100644 GIT binary patch delta 3283 zcmZ`*eN0=|759C9HpVt!%$Fg21=4^MKEhYBP!d8yL+A*lp(CwV#eK%lA7J}A*N-q9 z7eYwt05OCdsnzyJwY5{HNa?ByZR<)VHPxg<>c>`1(=<`CJ?Gy0?!EthOZdT$guHL%<(YNt=j%5<_xWu6kz$z4eaBRW0s}39 zI`d1#k0wG5%vS-gn!AW${bTc8{l0DgwuLEE2ZLeu7ZVuh?9>4tn;X|3Eks<#=n`-5NhO_ubj6Jm24NWZJFVY zRFn5%mY|mBRp6O?41d*AlGjBZ)=ubdc-Qk2QVRZYPg_=87BQXgmm_^4HKP)}~GdP7}4Gy&nNLJZ(m3L1;z5xby%*R^ITn>?|DF zj%+7(Lfhf6@1t+*LTV)gr4Y)= zdlgvfm!xS^kD=HgI;Wl%pj`=#fhtQ@1Q-c8%4N)he@LR4SlOqP&yjYo&j${ZR*W|6 zGMx-kd06qvT0qlQK;}yu!cj>Lq{R`2v>P^qgQN#KCYq|U211@SO4)=zryx&04~dCZ z(hIjI?(JMq+cXWTvO5~_y92VsM!b=kC_xk*gbu(DCsoUFtmp(nCDezG?tOGL+Rr@S zMIqk{f{oS1R<9qDp^afa$J_c-n4JmF1}ev5T5B`QbK2F{}cILrtFrp>%2Uoa#` zq_Dg*4dTn*M~s|36pG%?)J&{`O>fuJF$_u4`9thLlfCPIi`0`mTvVq>wao^V(dLr> zzfaFa%gQ%0`@>)(#Y7-=Y=^M#$^|RY^Q8Xf`2(#TEZok#EG(Oln@SO{626ZiL`KpH z`GmUH-RGNy)-Dt=hmK-4{*7P!?)MK8e>lRvDD5K+#)1)_%NUU&xcOg%jo8GY9n);Z zMVnIP(WoqYKgB`tc-G~a^`#_VpRX?!EA?i9de&c5-xBMFm}_$bp^kwocQin!JRz1K z`##V|hhWc4Eg6ERW)2u5*b#w?Gqq3Pfl4zFw~j`X=~^bM9UPaLl$YRx4`v!k2sUS) zw1gRd^Uo-XLTkLtqQ%Dc5Ih^dO^(5T<4wj8c1**8i?@tRXfDBni@Pn0oThOti8e9| zM-o+*7A;w(wQ{+9z9BZagSy#Df08&~i)TJcW!W1^+c(&Y+R=gL!J=X$<=882Uk2?fob7zcNS@7ezfrsW- zbEk})5QD)>he-?;E*-P1VCb#!KD{)oWyafBP`nMI^Cj??OSXz6zz?H>z3!h6~TMX_l9@I9+D*R`$Q&aKuV$ieHqE*VNe6Q_;zNIR7ZOLXF z$0C>E?WG3eJeod8FC8R{P`F%Ffz(X}A&Ray(2Aq=CLCRMSnw^g$zxssX}N){z~XX( z_`!I+ubLkpctq?ttoRG=6v)>nI{Xj4PJtFOJFTCTXKoRf**7JJ-0DnJj%i~4Mk`{B zZ-S8OCkhOtnvFk4_4^P{RX;RePgNQ5e4|}(H&scVfzMN2j8!6MZrqwC-BZ%8L5YR zYc*qcaO8rpq((!E8VY(^@RFzZaOfw|Wq;H)9*|?M9L7O|{t_95Sqxrcj1|#yb8zlM z3}QjR$1s2AQhc~le2P+hYtdSS-3Sc`Z3yiMoe13sy$Ht<@c!1WP`o|0dvpvfoM!4m da3gpS?(5jQntp=j_8f7`43*GKtnf6n{}1^$1dIRx delta 3376 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 diff --git a/test/forefire_helper.py b/test/forefire_helper.py index d833675..aa16fcd 100644 --- a/test/forefire_helper.py +++ b/test/forefire_helper.py @@ -16,6 +16,9 @@ def get_fuels_table(propagation_model): return RothermelAndrews2018FuelTable elif propagation_model == 'Rothermel': return standardRothermelFuelTable + elif propagation_model == 'ANNPropagationModel': + #TODO: fix for a more general use + return RothermelAndrews2018FuelTable else: raise NotImplementedError diff --git a/test/simulation.py b/test/simulation.py index 9575a6d..4428763 100644 --- a/test/simulation.py +++ b/test/simulation.py @@ -118,6 +118,7 @@ def __init__( fuel_type: float, slope: float, fire_front: List[List[float]], + nn_ros_model_path: Optional[str] = None, spatial_increment: Optional[float] = None, minimal_propagative_front_depth: Optional[float] = None, perimeter_resolution: Optional[float] = None, @@ -146,6 +147,8 @@ def __init__( self.ff.execute(domain_string) # Propagation model layer + if nn_ros_model_path: + self.ff["FFANNPropagationModelPath"] = nn_ros_model_path self.ff.addLayer( "propagation", self.ff["propagationModel"], diff --git a/test/tf_to_bin.py b/test/tf_to_bin.py index 20dc410..331c400 100644 --- a/test/tf_to_bin.py +++ b/test/tf_to_bin.py @@ -8,25 +8,27 @@ tf_model_path = sys.argv[1] bin_model_path = os.path.join(tf_model_path, 'saved_model.ffann') +rothermel_andrews_2018_input_names = [ + "fuel.fl1h_tac", + "fuel.fd_ft", + "fuel.Dme_pc", + "fuel.SAVcar_ftinv", + "fuel.H_BTUlb", + "fuel.totMineral_r", + "fuel.effectMineral_r", + "fuel.fuelDens_lbft3", + "fuel.mdOnDry1h_r", + "normalWind", + "slope" + ] + if not os.path.exists(bin_model_path): model = tf.keras.saving.load_model(tf_model_path) - import pdb; pdb.set_trace() save_model_structure( model, bin_model_path, - input_names=[ - "normalWind", # Normal wind - "slope", # Slope - "fuel.Md", # Fuel particle moisture content - "fuel.DeltaH", # Fuel particle low heat content - "fuel.sd", # Fuel Particle surface area to volume ratio (1/ft) - "fuel.e", # Fuel depth (ft) - "fuel.Rhod", # Ovendry particle density - "fuel.me", # Moisture content of extinction - "fuel.Sigmad" # Ovendry fuel loading - ], + input_names=rothermel_andrews_2018_input_names, output_names=['ROSx'] ) - # ['wind', 'slope', 'mdOnDry1h', 'H', 'SAVcar', 'fd', 'fuelDens', 'Dme', 'fl1h'] model, input_names, output_names = load_model_structure(bin_model_path) \ No newline at end of file diff --git a/test/uniform_simulation.py b/test/uniform_simulation.py index 3f4a199..8d93f51 100644 --- a/test/uniform_simulation.py +++ b/test/uniform_simulation.py @@ -6,6 +6,7 @@ def uniform_simulation(config): propagation_model = config['propagation_model'] + nn_ros_model_path = config['nn_ros_model_path'] if 'fuels_table' in config: fuels_table = fuels_table @@ -23,7 +24,6 @@ def uniform_simulation(config): minimal_propagative_front_depth = config['minimal_propagative_front_depth'] perimeter_resolution = config['perimeter_resolution'] relax = config['relax'] - smoothing = config['smoothing'] min_speed = config['min_speed'] burned_map_layer = config['burned_map_layer'] @@ -36,11 +36,11 @@ def uniform_simulation(config): fuel_type, slope, fire_front, + nn_ros_model_path, spatial_increment, minimal_propagative_front_depth, perimeter_resolution, relax, - smoothing, min_speed, burned_map_layer, ) From 7727dcb6efa146fefcd8cae30a21e35db66ecd29 Mon Sep 17 00:00:00 2001 From: Thoreau Romain Date: Tue, 10 Sep 2024 10:25:33 +0200 Subject: [PATCH 2/2] add simulation class with uniform wind --- configs/hill.yaml | 21 +++ .../forefire_helper.cpython-38.pyc | Bin 37793 -> 37793 bytes test/hill_simulation.py | 123 ++++++++++++++++++ test/simulation.py | 89 ++++++++++++- 4 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 configs/hill.yaml create mode 100644 test/hill_simulation.py diff --git a/configs/hill.yaml b/configs/hill.yaml new file mode 100644 index 0000000..8d45b08 --- /dev/null +++ b/configs/hill.yaml @@ -0,0 +1,21 @@ +# propagation_model: RothermelAndrews2018 +# nn_ros_model_path: +propagation_model: ANNPropagationModel +nn_ros_model_path: /home/ai4geo/Documents/nn_ros_models/nn_abs_256_RothermelAndrews2018/saved_model.ffann +fuel_type: [6, 7] +domain_width: 1000 +domain_height: 1000 +horizontal_wind: 200.0 +vertical_wind: 0.0 +nb_steps: 20 +step_size: 10 +fire_front: [[0, 550], [50, 500], [0, 450]] + +spatial_increment: 0.5 +perimeter_resolution: 2 # max distance between two nodes +minimal_propagative_front_depth: 5 # resolution of arrival time matrix +min_speed: 0.0 +max_speed: 100.0 +relax: 1 # takes 0.2 of the new ROS and 0.8 of the old ROS, to set in function of spatial_increment! +propagation_speed_adjustment_factor: 1 +burned_map_layer: diff --git a/test/__pycache__/forefire_helper.cpython-38.pyc b/test/__pycache__/forefire_helper.cpython-38.pyc index 02728f24cd251f446b0cae5f7fa2f9e3725960e0..5457b4fc264edde02b90510b2c95c329ea268ef8 100644 GIT binary patch delta 1866 zcmZ{lT}+!*7{@v7Tj<-SqkI<_1Ize$SvNrDM_GU{CL6+#=~zay2yffBw54C1mLVSj zCYyXXzV>*7cZ-R03CUt!$rj0Cyplw{&bI$4QJDS^fG{#<&$&kiAJElh;8=ny3fM;Zi=;19*fEeW8H8!15&&*T-4~O;c zLKEu?#G#9c&VZyE_N?prRjX04#yNl37owT_uBrmN+0eCqFfOuB}Pf5-lE81q|Kn8`UtRWzzz9YN(dE%qN`oTot4eO5L9p=dqx7wbaUf96C=R9Hw!tFBB7a zngxHl+jEXEL!9_iN_SprA$71MU2dsjR$9#<=xG+VYY@i}HpFqn2?WkVYZ1xoIO?&J zdU(_GWqJ{silKHe&#Xw3RTl>xf z{4_LRY{k&0)%fQE&6P<><6s-ZI?FPO<7pZ*;YbmoZLks8>Q>g9@IT80alI=Xj8G{W zRXha)J;z4r8N@4!or zpo??ih!l$JMyW3*(RQ30b!tRiT<`G(q>vbt{u`TkQVRETsDkv$T)2*yuqFaW_X^k= zIiC0bwVsXCl0J|l!#X@{aS(=W=I1eV(yqzUaF?d|B#vTrDb78(_3-;29!>t(#Lk!% zzKTvIFI4W0eal%pnQV6pp`2s>4KE#W2E>q?9S^k8PUsjbBb~B;j1Z$bq7Gjj-ykh= z`9uau-xJnN&N1PG$s-z7IHwACrkc!(VnyjQjJLqd^a;2!ovR9?s&HcZbybM!-H%Y% z2p6v9Li3CX{+T|!7e_9ed5@4z*t`~F;cDJ?V`pV{ol&^HrOvp9&Mw%w(IdCqc+3Q{ zZSE54X6H{aem4K2GTFEQp@kB#EEKBUqe}PU!Zy>CEH*P)aZu1uGmxbMb+?sADjUj|9+qQGD3(az9K7Tnlw9FJm^yfm=u(@s z8??(WSS~S%Bi$E_dc&g*cC?wuDN5D0m?^%rv=mW>s6^Bu>JbeHJE9q(Tu{85>P^85tzMU2Y~c!NAEF=OL~J9zPRn6T MY^~Dbp%n)H1z`=IZ~y=R delta 1868 zcmZ{kTTEP46o%Qu9GHu=Q*Iq@mP;u;bXuUL8mKVRVkvc6v9?$zjWCxp%nWm5&rswN zhDs|J%dN{7e5)qbCM1nHk~WgY_#}z?pbr|ySViLlN&C>m2kV2n);R=bOd;W$z4rRo zT6>?h_r7^cbMuzQcp)pxkcNN%e(>NE<0Hlr@Pv&rJ-np}Fr)m3#v&N?=;jIxP^@zo z>_A&&b|L0)1|-$7;a$|tmp`L;6Iy@R7viSPP*p)@4!o>yWw|h~zoXktVu9yDo1xp3 zREKl|+%+^XL4IubBE5Rcw>6@5b2H*B{zo;4v}|sM$AUcJd4-hPbgM>qb8Up3vwS?q-?DaIT!|jXdKmN!en*x0W@^A9))X z?*CU`zFF0wI3WZhj+i&0?LhKI*x_$yFTh2=B_)2&-@>f$t^doE*$;awSsTvg!q2_k z#^Y4_gj)Yppm|@?qG_@fv52dT>Tr;zF)=MGWV{uY0xM^g{cgpdLP0|33I`)xibj=4 z(ZJhrmcK+esrb2Lpv&!uIh4a%Hzj?yf3ms9SZmHR*Z_{+#oO?bvC;OppU z@6YstSkW=Tsr7*FPp^;V8uzV$k<*MIylQB2Gh!n4`s2LY1*ad6XI%Mm$hbWLO6P=_R zpFD>AeDXOZ*^mgKsS+?x6{zN3#XLW?ikgz?X5^*mCgl6mcQD22cgtC!^2wk6{h?F@`C0-#mxN*>ItV7iCVi}a`#BCa3IX>dXK}U4*4sPK6}*sI!f#r zzF^cF9FOv4tJ8M_4gjojt*tVRaVN0(U8^LH5l3#n?IMTBxjSpm>8TAUQ%^ z0bfY6XX5n;VpEe34BTF5)Z2wne=stLsUI#hvSUznV=``}d;)>qeNGQKr>B|ITgyuc zWrQk19pNycp3q3J5|j%{cT>G7bfMMj(n%xQA-5B{2u{K(;hVG^...', x-mean, np.linalg.inv(cov), x-mean)) + gaussian = exp / den + altitude = height * (gaussian - gaussian.min()) / (gaussian.max() - gaussian.min()) + return altitude + + +def hill_simulation(config): + propagation_model = config['propagation_model'] + nn_ros_model_path = config['nn_ros_model_path'] + + if 'fuels_table' in config: + fuels_table = fuels_table + else: + fuels_table = get_fuels_table(propagation_model) + fuel_type = config['fuel_type'] + domain_width = config['domain_width'] + domain_height = config['domain_height'] + domain = (0, 0, domain_width, domain_height) + + # Create hill with a 2D gaussian + mean = np.array([domain_height // 2, domain_width //2]) + cov = np.array([ + [1e5, 0], + [0, 1e5]]) + + map_x, map_y = np.meshgrid( + np.arange(domain_height), + np.arange(domain_width) + ) + + map = np.empty(map_x.shape + (2,)) + map[:, :, 0] = map_x + map[:, :, 1] = map_y + + altitude_map = hill(map, mean, cov) + # plt.imshow(altitude_map); plt.show() + + fuel_map = np.ones_like(altitude_map) + fuel_map[:, :domain_width // 2] = fuel_type[0] + fuel_map[:, :domain_width // 2] = fuel_type[1] + + horizontal_wind = config['horizontal_wind'] + vertical_wind = config['vertical_wind'] + + fire_front = config['fire_front'] + spatial_increment = config['spatial_increment'] + minimal_propagative_front_depth = config['minimal_propagative_front_depth'] + perimeter_resolution = config['perimeter_resolution'] + relax = config['relax'] + min_speed = config['min_speed'] + burned_map_layer = config['burned_map_layer'] + + simulation = UniformWindForeFireSimulation( + propagation_model, + fuels_table, + horizontal_wind, + vertical_wind, + fuel_map, + altitude_map, + fire_front, + nn_ros_model_path, + spatial_increment, + minimal_propagative_front_depth, + perimeter_resolution, + relax, + min_speed, + burned_map_layer, + ) + + nb_steps = config['nb_steps'] + step_size = config['step_size'] + + # Run simulation + pathes = simulation(nb_steps, step_size) + + ##----------------------------------------------------------------------------- + ## Plot the simulated Fronts + ##----------------------------------------------------------------------------- + plotExtents = ( + float(simulation.ff["SWx"]), + float(simulation.ff["SWx"]) + float(simulation.ff["Lx"]), + float(simulation.ff["SWy"]), + float(simulation.ff["SWy"]) + float(simulation.ff["Ly"])) + plot_simulation(pathes, simulation.fuel_map[0, 0], simulation.altitude_map[0, 0], plotExtents, None) + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--config', type=str, + help='Path to the config file (.yaml) of the simulation.') + parser.add_argument('--propagation_model', type=str, default='RothermelAndrews2018', + help='Rate of Spread model (default: RothermelAndrews2018)') + parser.add_argument('--fuel_type', type=int, default=6, + help='Index of the fuel type to use (default: 6)') + parser.add_argument('--domain_width', type=int) + parser.add_argument('--domain_height', type=int) + parser.add_argument('--horizontal_wind', type=float) + parser.add_argument('--vertical_wind', type=float) + parser.add_argument('--slope', type=float) + parser.add_argument('--nb_steps', type=int, + help='Number of simulation steps') + parser.add_argument('--step_size', type=float, + help='Duration (in seconds) between each step.') + args = parser.parse_args() + + if args.config: + with open(args.config, 'r') as stream: + config = yaml.safe_load(stream) + else: + config = vars(args) + + hill_simulation(config) \ No newline at end of file diff --git a/test/simulation.py b/test/simulation.py index 4428763..476b50c 100644 --- a/test/simulation.py +++ b/test/simulation.py @@ -7,6 +7,7 @@ import pyforefire as forefire from forefire_helper import * +import pdb logging.basicConfig(stream=sys.stdout, level=logging.INFO) logger = logging.getLogger() @@ -18,7 +19,6 @@ class ForeFireSimulation: def __init__( self, propagation_model: str, - domain: Tuple[int], fuels_table: callable, spatial_increment: Optional[float] = None, minimal_propagative_front_depth: Optional[float] = None, @@ -45,7 +45,7 @@ def __init__( # Initialize pyforefire module ff = forefire.ForeFire() ff["propagationModel"] = propagation_model - ff["SWx"], ff["SWy"], ff["Lx"], ff["Ly"] = domain + # ff["SWx"], ff["SWy"], ff["Lx"], ff["Ly"] = domain ff["fuelsTable"] = fuels_table() if spatial_increment: @@ -129,7 +129,6 @@ def __init__( ): super().__init__( propagation_model, - domain, fuels_table, spatial_increment, minimal_propagative_front_depth, @@ -141,6 +140,7 @@ def __init__( # Instantiate domain domain_height, domain_width = domain[-1], domain[-2] + self.ff["SWx"], self.ff["SWy"], self.ff["Lx"], self.ff["Ly"] = domain domain_string = \ f'FireDomain[sw=({self.ff["SWx"]},{self.ff["SWy"]},0);ne=({self.ff["SWx"] + self.ff["Lx"]},{self.ff["SWy"] + self.ff["Ly"]},0);t=0]' logger.info(domain_string) @@ -176,6 +176,89 @@ def __init__( self.altitude_map[:, :, :] = np.linspace(0, domain_width, domain_width // data_resolution) * math.tan(slope) self.ff.addScalarLayer("table", "altitude", 0, 0, 0, domain_width, domain_height, 0, self.altitude_map) + # Instantiate fire front (front orentation is clockwise!!) + self.ff.execute(f"\tFireFront[id=2;domain=0;t=0]") + for (xp, yp) in fire_front: + self.ff.execute(f"\t\tFireNode[domain=0;loc=({xp},{yp},0);vel=(0,0,0);t=0;state=init;frontId=2]") + logger.info(f'Initial fire front: {fire_front}') + + +class UniformWindForeFireSimulation(ForeFireSimulation): + """ + Class for a ForeFire simulation with uniform wind, uniform fuel (only one fuel type) + and uniform slope. + """ + def __init__( + self, + propagation_model: str, + fuels_table: callable, + horizontal_wind: float, + vertical_wind: float, + fuel_map: np.ndarray, + altitude_map: np.ndarray, + fire_front: List[List[float]], + nn_ros_model_path: Optional[str] = None, + spatial_increment: Optional[float] = None, + minimal_propagative_front_depth: Optional[float] = None, + perimeter_resolution: Optional[float] = None, + relax: Optional[float] = None, + min_speed: Optional[float] = None, + burned_map_layer: Optional[int] = None, + ): + super().__init__( + propagation_model, + # domain, + fuels_table, + spatial_increment, + minimal_propagative_front_depth, + perimeter_resolution, + relax, + min_speed, + burned_map_layer, + ) + + # Instantiate domain + domain_height, domain_width = fuel_map.shape + self.ff["SWx"] = 0 + self.ff["SWy"] = 0 + self.ff["Lx"] = domain_width + self.ff["Ly"] = domain_height + domain_string = \ + f'FireDomain[sw=({self.ff["SWx"]},{self.ff["SWy"]},0);ne=({self.ff["SWx"] + self.ff["Lx"]},{self.ff["SWy"] + self.ff["Ly"]},0);t=0]' + logger.info(domain_string) + self.ff.execute(domain_string) + + # Propagation model layer + if nn_ros_model_path: + self.ff["FFANNPropagationModelPath"] = nn_ros_model_path + self.ff.addLayer( + "propagation", + self.ff["propagationModel"], + "propagationModel") + logger.info(f'ROS model: {propagation_model}') + + # Wind layers + self.ff["windU"] = horizontal_wind + self.ff["windV"] = vertical_wind + self.ff.addLayer("data","windU","windU") + self.ff.addLayer("data","windV","windV") + logger.info(f'Uniform wind conditions: horizontal wind: {horizontal_wind} m/s | vertical wind: {vertical_wind} m/s') + + # Fuel layer + self.fuel_map = fuel_map.reshape(1, 1, domain_height, domain_width) + self.ff.addIndexLayer( + "table", + "fuel", float(self.ff["SWx"]), float(self.ff["SWy"]), 0, float(self.ff["Lx"]), float(self.ff["Ly"]), 0, + self.fuel_map) + logger.info(f'Fuel map types: {list(np.unique(self.fuel_map))}') + + # Altitude layer + self.altitude_map = altitude_map.reshape(1, 1, domain_height, domain_width) + self.ff.addIndexLayer( + "data", + "altitude", float(self.ff["SWx"]), float(self.ff["SWy"]), 0, float(self.ff["Lx"]), float(self.ff["Ly"]), 0, + self.altitude_map) + # Instantiate fire front (front orentation is clockwise!!) self.ff.execute(f"\tFireFront[id=2;domain=0;t=0]") for (xp, yp) in fire_front: