QUIC-Fire-TT / ttrs_quicfire

ttrs_quicfire is a Python library to easily configure burn models for plots of land defined using shape files for the quicfire model.
MIT License
0 stars 1 forks source link

Ignition: Building_Black #5

Closed zacharycope0 closed 2 years ago

zacharycope0 commented 2 years ago

Feature Description I'd like to implement and initial ignition that runs along the downwind portion of the domain before lighting the strip ignitions. This is typically called 'building black' and is used to widen the fuel break and decrease the likelihood that the burn jumps outside the unit. Alex has code to select the portion of the domain to ignite but you will probably have to implement the rest:

If you have use for selecting parts of a polyline within a shapefile, I got it working. Key lines are 88 - 128 in QUIC-Fire-TT/TT_PY_Scripts/AM_scripts/ign_module_v2.py on GitHub. You will need to provide ring_thetas[0] and ring_thetas[1] in a clockwise direction such that ring_thetas[0] < ring_thetas[1]. This is the wedge you want to select, default is set to ring_thetas = [0.0, 360.0]. Lines 120 through 128 are the diagnostic plotting I had to use to debug: Capture04 Feel free to pull that routine out but bear in mind I'm steaming towards v3 of this ign_module with structural changes to how the looping will work. So hopefully it will get cleaner and better overall to use functions I've written more easily.

Getting Started

  1. Since fuel around the domain is removed you will first want to build a smaller version of the burn_plot.shp This was my solution for clipping the ignition lines that fell within 6m of the burn_plot boudary. You may be able to use it to use the same function to clip the outer portion of a polygon too: https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/e923b1bfc659b0a50c5449720e65b78de67da6db/ttrs_quicfire/build_shapefiles.py#L265-L271 You may need to convert back and forth between polygons and lines so use these functions if needed: https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/e923b1bfc659b0a50c5449720e65b78de67da6db/ttrs_quicfire/build_shapefiles.py#L57-L71
  2. Add points along the line https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/e923b1bfc659b0a50c5449720e65b78de67da6db/ttrs_quicfire/build_shapefiles.py#L275
  3. Timing the points will be a little tricky. I currently sort the points using the x or y coordinate since the ignition are moving toward a cardinal direction. The edge of the domain might snake so you will have to start at one end and and move along the line to the next location to figure out the ignition order. You may have to use a nearest neighbors approach if needed, but I can think of instances where this might fail.

This is my current timing protocol: https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/e923b1bfc659b0a50c5449720e65b78de67da6db/ttrs_quicfire/quic_fire.py#L299

  1. See if you can add the 'building black' ignition points to the ignition protocol so that the strip ignitions start after the we build black.

Screenshots Add any other context or screenshots about the feature request here.

zacharycope0 commented 2 years ago

@mathfire as I described in Getting Started Step 3: Could you share the approach/code you used to sort the points along the line. I think I remember you saying you used nearest neighbors.

mathfire commented 2 years ago

@zacharycope0 @cbonesteel Cool! This is a good task to be tackling. Keep in mind the standard workflow utilizes class structures that will not match-up with my Python scripts. Feel free to splice in my code where needed, even if that breaks up my functions, it is better to match the class structures in the standard workflow for sure!

My version of this code: https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/12c4352a1bd1cb7c0c386557907e3eee6d89221f/ttrs_quicfire/quic_fire.py#L299

... specifically lines 334 - 346 within ttrs_quicfire/quic_fire.py are a little more expansive in my version. It creates a copy of the ignition lists - x and y are done separately - then destructs the lists using xx.pop(next_idx) and yy.pop(next_idx). I use xx and yy out of a good (or bad, hahaha) habit to create easily searchable variable names, nothing special there. A post-iteration decision is made using a Euclidean distance on xx and yy about the nearest neighbor to set next_idx and then next_idx is popped off of xx and yy to move onto the next point in the sequence. Look for lines 336 - 410 to see how I have been doing that: https://github.com/QUIC-Fire-TT/TT_PY_Scripts/blob/e329a9d19ead89c3c8147b8d00d5537234fe549a/AM_scripts/ign_module_v2.py#L336-L410

Note: I may have to edit this comment so you can see the code snippets. Let me know if that is problematic. One, my code lives in TT_PY_Scripts/AM_scripts/ and two, I am used to referencing code in pull requests, but not these comments. We shall see...

cbonesteel commented 2 years ago

@mathfire From my experience code outside the repository does not show up as a code snippet. It could possibly be that it is a private repo as well but I do have access to the repository so when I click the link it takes me to the intended reference and highlights it. Others may have an issue with it but inside the organization this is fine. Thanks for the help! I'll defenitely be using it as I begin to tackle this problem.

zacharycope0 commented 2 years ago

@cbonesteel Alex's code is in our private working repo. I think you would be able to access it since it falls with within the larger organization. However I copied his script into the build_black_better branch to ensure that you have it.

https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/04b2c728b3333805e44a0a52f2afbd12465f5854/AlexsCode/ign_module_v2.py#L336-L410

cbonesteel commented 2 years ago

I am exploring the ign_module_v2.py script and am running into issues with this line.

https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/04b2c728b3333805e44a0a52f2afbd12465f5854/AlexsCode/ign_module_v2.py#L97

Python cannot cannot find the hausdorff_distance function and I cannot find evidence of it existing within geopandas, both in the api and in online forms. Is this a geopandas function that has been depricated or am I missing this from somewhere else?

mathfire commented 2 years ago

Hmmm... good observation! It is probably just what you said, a versioning issue. hausdorff_diastance is an object method from the Shapely package 1.8.2 ( more info via this link: https://shapely.readthedocs.io/en/stable/manual.html )

In general it is the max distance between arrays. Applied in this code, it will give the maximum distance between a line (or polygon) and the centroid point

Looks like there is an equivalent scipy method (more info via this link: https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.directed_hausdorff.html )

image

My purpose of using hausdorff_distance is to make sure the entire ignition line portion falling between ring_thetas[0] and ring_thetas[1] will intersect the scan annulus that gets built. To that end I add a little bit extra padding when I take np.ceil() of the hausdorff_distance. A couple other work-arounds might be:

Hope that helps!

cbonesteel commented 2 years ago

I got it to select part of the border based on the wedge. This is shown below: mask ignition

Here is the functions for quick reference:

https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/a27a228546e4f15132c6b0f6a8ba7a9293a5f77c/ttrs_quicfire/quic_fire.py#L210

https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/a27a228546e4f15132c6b0f6a8ba7a9293a5f77c/ttrs_quicfire/build_shapefiles.py#L275

@zacharycope0 and I discussed how to make the side of the unit that is selected automatic based on wind and this might be a little tricky. For now, it has to be selected based on a 0-360 degree selection from the centroid of the unit. The implementation creates a fuel break by making fuels 0 within 5 meters of the selected border on the inside of the unit only. I don't know how to easily display the fuel arrays so I can see if this worked, but I imagine it is correct. The only thing that might need to change is the buffer from -5 to 5 if it buffers the wrong side.

https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/a27a228546e4f15132c6b0f6a8ba7a9293a5f77c/ttrs_quicfire/quic_fire.py#L228

If there is any way we can check this buffer before I make a pull request that would be great. This way I can prepare documentation changes and the likes for the pull request as well.

mathfire commented 2 years ago

Way cool! I like how everything is situated in the code. My only question: at how many locations would I need to change ring_thetas to reproduce the picture? Looks like the picture has ring_thetas = [0.0, 135.0] or thereabouts. How many times do I type that array in so that becomes the selected part? Maybe that question doesn't make sense if scripting, I'm not sure... Great job on this progress. Thanks~

zacharycope0 commented 2 years ago

@cbonesteel. You should use matplotlib to visualize the the fuels array to make sure that it's doing what you expect:

arr = data[zIndex,:,:] plt.figure() plt.imshow(arr,origin='lower') plt.colorbar() plt.clim([0,MAX]) plt.savefig("plot.png") plt.close()

cbonesteel commented 2 years ago

@mathfire You are spot on, I used [0.0, 130.0] for the picture there. This will be included in the documentation but basically in the main.py file you would just include something like this:

qf_arrs.build_black(wind_dir=225, ring_thetas=[0.0, 130.0])

This is the only command the script needs and from there it modifies the fuels to be accurate.

mathfire commented 2 years ago

@cbonesteel Nice! That makes good sense, I see how the defaults would work towards [0.0, 360.0] in this case. Keep your eye out for when [0.0, 360.0] because I was getting some weird behavior in the clip functions. I have been careful to always test this case to make sure it doesn't crash on me. Thanks!

zacharycope0 commented 2 years ago

@cbonesteel edited my post cause it didn't include the code snippet. I think you've seen it now. FYI the once the dat files are read in the indexing is arr[z,y,x] and indexing for x in y starts in the SW (bottom left corner). That's why we use origin='lower'.

I should add that when we build black we should only remove fuel that intersects the surfaces cells (z=0) since the low intensity fire wouldn't impact the canopy. My build_fuelbreak() function currently loops through and removes fuels from the entire column of cells above the break. https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/dd7864cbc3d0fee9df67831639d11a408b12c0f3/ttrs_quicfire/quic_fire.py#L205-L209

cbonesteel commented 2 years ago

Alright, I checked the direction using the fuel break and a larger build_black buffer and it was on the correct side. plot

I also went ahead and changed it to only be on the z=0 layer for each array. I will open a pull request with all the details and documentation early tomorrow for one final review. https://github.com/QUIC-Fire-TT/ttrs_quicfire/blob/27f712481ec4ffd33ff70410823f38169f3af5b1/ttrs_quicfire/quic_fire.py#L233-L235