danielle-losos commited on
Commit
12c1144
·
verified ·
1 Parent(s): 7c81fc2

Delete burn_mapper

Browse files
burn_mapper/.DS_Store DELETED
Binary file (6.15 kB)
 
burn_mapper/.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/.github/workflows/sync-hf.yml DELETED
@@ -1,20 +0,0 @@
1
- name: Sync to Hugging Face hub
2
- on:
3
- push:
4
- branches: [main]
5
-
6
- # to run this workflow manually from the Actions tab
7
- workflow_dispatch:
8
-
9
- jobs:
10
- sync-to-hub:
11
- runs-on: ubuntu-latest
12
- steps:
13
- - uses: actions/checkout@v3
14
- with:
15
- fetch-depth: 0
16
- lfs: true
17
- - name: Push to hub
18
- env:
19
- HF_TOKEN: ${{ secrets.HF_TOKEN }}
20
- run: git push --force https://giswqs:[email protected]/spaces/giswqs/solara-geemap main
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/.gitignore DELETED
@@ -1,161 +0,0 @@
1
- # Byte-compiled / optimized / DLL files
2
- __pycache__/
3
- *.py[cod]
4
- *$py.class
5
-
6
- # C extensions
7
- *.so
8
-
9
- # Distribution / packaging
10
- .Python
11
- build/
12
- develop-eggs/
13
- dist/
14
- downloads/
15
- eggs/
16
- .eggs/
17
- lib/
18
- lib64/
19
- parts/
20
- sdist/
21
- var/
22
- wheels/
23
- share/python-wheels/
24
- *.egg-info/
25
- .installed.cfg
26
- *.egg
27
- MANIFEST
28
- private/
29
-
30
- # PyInstaller
31
- # Usually these files are written by a python script from a template
32
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
- *.manifest
34
- *.spec
35
-
36
- # Installer logs
37
- pip-log.txt
38
- pip-delete-this-directory.txt
39
-
40
- # Unit test / coverage reports
41
- htmlcov/
42
- .tox/
43
- .nox/
44
- .coverage
45
- .coverage.*
46
- .cache
47
- nosetests.xml
48
- coverage.xml
49
- *.cover
50
- *.py,cover
51
- .hypothesis/
52
- .pytest_cache/
53
- cover/
54
-
55
- # Translations
56
- *.mo
57
- *.pot
58
-
59
- # Django stuff:
60
- *.log
61
- local_settings.py
62
- db.sqlite3
63
- db.sqlite3-journal
64
-
65
- # Flask stuff:
66
- instance/
67
- .webassets-cache
68
-
69
- # Scrapy stuff:
70
- .scrapy
71
-
72
- # Sphinx documentation
73
- docs/_build/
74
-
75
- # PyBuilder
76
- .pybuilder/
77
- target/
78
-
79
- # Jupyter Notebook
80
- .ipynb_checkpoints
81
-
82
- # IPython
83
- profile_default/
84
- ipython_config.py
85
-
86
- # pyenv
87
- # For a library or package, you might want to ignore these files since the code is
88
- # intended to run in multiple environments; otherwise, check them in:
89
- # .python-version
90
-
91
- # pipenv
92
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
- # install all needed dependencies.
96
- #Pipfile.lock
97
-
98
- # poetry
99
- # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
100
- # This is especially recommended for binary packages to ensure reproducibility, and is more
101
- # commonly ignored for libraries.
102
- # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
103
- #poetry.lock
104
-
105
- # pdm
106
- # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
107
- #pdm.lock
108
- # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
109
- # in version control.
110
- # https://pdm.fming.dev/#use-with-ide
111
- .pdm.toml
112
-
113
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
114
- __pypackages__/
115
-
116
- # Celery stuff
117
- celerybeat-schedule
118
- celerybeat.pid
119
-
120
- # SageMath parsed files
121
- *.sage.py
122
-
123
- # Environments
124
- .env
125
- .venv
126
- env/
127
- venv/
128
- ENV/
129
- env.bak/
130
- venv.bak/
131
-
132
- # Spyder project settings
133
- .spyderproject
134
- .spyproject
135
-
136
- # Rope project settings
137
- .ropeproject
138
-
139
- # mkdocs documentation
140
- /site
141
-
142
- # mypy
143
- .mypy_cache/
144
- .dmypy.json
145
- dmypy.json
146
-
147
- # Pyre type checker
148
- .pyre/
149
-
150
- # pytype static type analyzer
151
- .pytype/
152
-
153
- # Cython debug symbols
154
- cython_debug/
155
-
156
- # PyCharm
157
- # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
158
- # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
159
- # and can be added to the global gitignore or merged into this file. For a more nuclear
160
- # option (not recommended) you can uncomment the following to ignore the entire idea folder.
161
- #.idea/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/Dockerfile DELETED
@@ -1,30 +0,0 @@
1
- FROM jupyter/base-notebook:latest
2
-
3
- # Install required packages
4
- RUN mamba install -c conda-forge leafmap geopandas localtileserver -y && \
5
- fix-permissions "${CONDA_DIR}" && \
6
- fix-permissions "/home/${NB_USER}"
7
-
8
- # Copy the requirements file and install dependencies
9
- COPY requirements.txt .
10
- RUN pip install -r requirements.txt
11
-
12
- # Copy the entire project directory into the container
13
- COPY . /home/${NB_USER}
14
-
15
- # Set the working directory
16
- WORKDIR /home/${NB_USER}
17
-
18
- # Set the PROJ_LIB environment variable
19
- ENV PROJ_LIB='/opt/conda/share/proj'
20
-
21
- # Ensure the notebook user owns the home directory
22
- USER root
23
- RUN chown -R ${NB_UID} ${HOME}
24
- USER ${NB_USER}
25
-
26
- # Expose the port for Solara
27
- EXPOSE 8765
28
-
29
- # Run the Solara app
30
- CMD ["solara", "run", "pages", "--host=0.0.0.0"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Open Geospatial Solutions
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/README.md DELETED
@@ -1,58 +0,0 @@
1
- ---
2
- title: Solara Geemap
3
- emoji: 🏃
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- app_port: 8765
10
- ---
11
-
12
- ## Earth Engine Web Apps
13
-
14
- ### Introduction
15
-
16
- **A collection of Earth Engine web apps developed using [Solara](https://github.com/widgetti/solara) and geemap**
17
-
18
- - Web App: <https://giswqs-solara-geemap.hf.space>
19
- - GitHub: <https://github.com/opengeos/solara-geemap>
20
- - Hugging Face: <https://huggingface.co/spaces/giswqs/solara-geemap>
21
-
22
- ### How to deploy this app on Hugging Face Spaces
23
-
24
- 1. Go to <https://huggingface.co/spaces/giswqs/solara-geemap/tree/main> and duplicate the space to your own space.
25
-
26
- ![](https://i.imgur.com/gTg4V2x.png)
27
-
28
- 2. You need to set `EARTHENGINE_TOKEN` in order to use Earth Engine. The token value should be copied from the following file depending on your operating system:
29
-
30
- ```text
31
- Windows: C:\\Users\\USERNAME\\.config\\earthengine\\credentials
32
- Linux: /home/USERNAME/.config/earthengine/credentials
33
- MacOS: /Users/USERNAME/.config/earthengine/credentials
34
- ```
35
-
36
- Simply open the file and copy **ALL** the content to the `EARTHENGINE_TOKEN` environment variable.
37
-
38
- ![](https://i.imgur.com/i04gzyH.png)
39
-
40
- ![](https://i.imgur.com/Ex37Ut7.png)
41
-
42
- Alternatively, you can run the following code to retrieve your Earth Engine token:
43
-
44
- ```python
45
- import geemap
46
- geemap.get_ee_token()
47
- ```
48
-
49
- Copy all the content of the printed token and set it as the `EARTHENGINE_TOKEN` environment variable.
50
-
51
- 3. After the space is built successfully, click the `Embed this Space` menu and find the `Direct URL` for the app, such as <https://giswqs-solara-geemap.hf.space>.
52
-
53
- ![](https://i.imgur.com/DNM36sk.png)
54
-
55
- ![](https://i.imgur.com/KX82lSf.png)
56
-
57
- 4. Add your own apps (\*.py) to the `pages` folder.
58
- 5. Commit and push your changes to the repository. Wait for the space to be built successfully.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/__init__.py DELETED
File without changes
burn_mapper/pages/Home.py DELETED
@@ -1,44 +0,0 @@
1
- import solara
2
-
3
- @solara.component
4
- def Page():
5
- with solara.Column(align="center"):
6
- markdown = """
7
- ## Real-time wildfire burn mapping
8
-
9
- ### About the project
10
-
11
- **A proof of concept illustrating wildfire burn severity maps with emerging clarity while the fires progress.
12
- Target users are forecasters and emergency managers responding to post-fire risks including debris flows and landslides.**
13
-
14
- More project description, etc, etc.
15
-
16
- **Case Studies from 2020 and 2021 Western US wildfire seasons **
17
-
18
- - August Complex, CA (2020)
19
- - Cameron Peak, CO (2020)
20
- - Dixie Fire, CA (2021)
21
- - North Complex, CA (2020)
22
-
23
-
24
- **Current 2024 wildfires over 10,000 acres **
25
-
26
- ### How to use the app
27
-
28
- 1. Select the fire from the drop-down menu
29
-
30
- 2. Export image to Google Drive as a geotiff
31
-
32
- 3.
33
-
34
- ### Support
35
-
36
- Initial funding for wildland burn scar mapping came through the NOAA JPSS/RRPG Fire and Smoke Initiative.
37
- This supported the initial tests of BRIDGE maps using dNDVI. Subsequent funding supported the development of dNBR mapping and an effort
38
- to tie support the near real-time distribution of incident-based fire detection and related satellite imagery products through the Next Generation Fire System (NGFS).
39
- Current funding from the NOAA Weather Program Office (WPO) is supporting the refinement of our Google Earth Engine App (GEE)
40
- and integration of GEE burn scar output with AWIPS (see example above) for Weather Forecast Offices, Regional Offices, and the Weather Prediction Center.
41
-
42
- """
43
-
44
- solara.Markdown(markdown)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/pages/__init__.py DELETED
File without changes
burn_mapper/pages/__pycache__/NBR_calculations.cpython-312.pyc DELETED
Binary file (6.87 kB)
 
burn_mapper/pages/current_fires.py DELETED
@@ -1,399 +0,0 @@
1
- import ee
2
- import geemap
3
- import solara
4
- import ipywidgets as widgets
5
- import datetime
6
-
7
- #from NBR_calculations import GcalcNBR, VcalcNBR, LcalcNBR, ScalcNBR, GcalcCCsingle
8
- import requests
9
-
10
- # Bit-masking
11
- BitMask_0 = 1 << 0
12
- BitMask_1 = 1 << 1
13
- BitMask_2 = 1 << 2
14
- BitMask_3 = 1 << 3
15
- BitMask_4 = 1 << 4
16
- BitMask_5 = 1 << 5
17
- BitMask_6 = 1 << 6
18
- BitMask_7 = 1 << 7
19
- BitMask_8 = 1 << 8
20
- BitMask_9 = 1 << 9
21
-
22
- def GcalcCCsingle (goesImg):
23
-
24
- fireDQF = goesImg.select('DQF').int()
25
- CMI_QF3 = goesImg.select('DQF_C03').int()
26
- CMI_QF6 = goesImg.select('DQF_C06').int()
27
-
28
- #Right now, cloud mask is excluding clouds and water; active fire, bad data and fire free are unmasked. NBR mask exlcudes fire
29
- F_Mask = fireDQF.eq(0)
30
- C_Mask = (fireDQF.lt(2).Or(fireDQF.gt(2))).rename('C_Mask')
31
- #.And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('C_Mask')
32
- QF_Mask = (fireDQF.eq(1).Or(fireDQF.gt(3)))\
33
- .And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('QFmask')
34
-
35
- GOESmasked = goesImg.select(['CMI_C03','CMI_C06']).updateMask(QF_Mask)
36
- NBRmasked = GOESmasked.normalizedDifference(['CMI_C03', 'CMI_C06']).toFloat().rename('NBR')
37
- cloudMasked = goesImg.select('CMI_C03').updateMask(C_Mask).toFloat().rename('CC')
38
- fireMasked = goesImg.select('CMI_C03').updateMask(F_Mask).toFloat().rename('FC')
39
-
40
- return goesImg.addBands([NBRmasked,cloudMasked, fireMasked,QF_Mask,C_Mask])
41
-
42
- '''Parameter Array Name Value Bit(s) = Value
43
- Sun Glint QF1 Surface Reflectance None 6-7 = 00
44
- Low Sun Mask QF1 Surface Reflectance High 5 = 0
45
- Day/Night QF1 Surface Reflectance Day 4 =0
46
- Cloud Detection QF1 Surface Reflectance Confident Clear 2-3 = 00 or Problably Clear 2-3 = 01
47
- Cloud Mask Quality QF1 Surface Reflectance High or Medium 0-1 = 10 or 11
48
- Snow/Ice QF2 Surface Reflectance No Snow or Ice 5 = 0
49
- Cloud Shadow QF2 Surface Reflectance No Cloud Shadow 3 = 0
50
- LandWater QF2 Surface Reflectance Land, Snow, Arctic, Antarctic or Greenland, Desert 0-2 = 011, 100, 101, 110, 111
51
- Thin Cirrus Flag QF7 Surface Reflectance No Thin Cirrus 4 = 0
52
- Aerosol Quantity QF7 Surface Reflectance Climatology, Low or Medium 2-3 = 00, 01 or 10
53
- Adjacent to Cloud QF7 Surface Reflectance Not Adjacent to Cloud 1 = 0'''
54
-
55
- def VcalcNBR (VIIRSimg):
56
-
57
- QF1 = VIIRSimg.select('QF1').int()
58
- QF2 = VIIRSimg.select('QF2').int()
59
- QF7 = VIIRSimg.select('QF7').int()
60
-
61
- QF_Mask = (QF1.bitwiseAnd(BitMask_3).eq(0)).And\
62
- ((QF2.bitwiseAnd(BitMask_2).eq(4)).Or((QF2.bitwiseAnd(BitMask_1).eq(0)))).And\
63
- (QF2.bitwiseAnd(BitMask_5).eq(0)).rename('QFmask');
64
-
65
- VIIRSm = VIIRSimg.select(['I2','M11']).updateMask(QF_Mask);
66
- NBR = VIIRSm.normalizedDifference(['I2','M11']).toFloat().rename('NBR')
67
- return VIIRSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)
68
-
69
- ''' Bit 1: Dilated Cloud
70
- Bit 2: Cirrus (high confidence)
71
- Bit 3: Cloud
72
- Bit 4: Cloud Shadow
73
- Bit 5: Snow
74
- Bit 6: Clear (0: Cloud or Dilated Cloud bits are set, 1: Cloud and Dilated Cloud bits are not set)
75
- Bit 7: Water
76
- Bits 8-9: Cloud Confidence (0: None, 1: Low, 2: Medium, 3: High)
77
- Bits 10-11: Cloud Shadow Confidence (0: None, 1: Low, 2: Medium, 3: High)
78
- Bits 12-13: Snow/Ice Confidence (0: None, 1: Low, 2: Medium, 3: High)
79
- Bits 14-15: Cirrus Confidence (0: None, 1: Low, 2: Medium, 3: High)'''
80
-
81
- def LcalcNBR (LSimg):
82
- QApixel = LSimg.select('QA_PIXEL').int()
83
- QF_Mask =(QApixel.bitwiseAnd(BitMask_3).eq(0)).And\
84
- (QApixel.bitwiseAnd(BitMask_5).eq(0)).And\
85
- (QApixel.bitwiseAnd(BitMask_7).eq(0)).rename('QFmask');
86
-
87
- LSmasked = LSimg.select(['SR_B5','SR_B7']).updateMask(QF_Mask);
88
- NBR = LSmasked.normalizedDifference(['SR_B5','SR_B7']).toFloat().rename('NBR')
89
- return LSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)
90
-
91
- ''' 1 Saturated or defective
92
- 2 Dark Area Pixels
93
- 3 Cloud Shadows
94
- 4 Vegetation
95
- 5 Bare Soils
96
- 6 Water
97
- 7 Clouds Low Probability / Unclassified
98
- 8 Clouds Medium Probability
99
- 9 Clouds High Probability
100
- 10 Cirrus
101
- 11 Snow / Ice'''
102
-
103
- def ScalcNBR (sentImg):
104
- SCL = sentImg.select('SCL');
105
- QF_Mask =(SCL.neq(6)).And\
106
- (SCL.neq(8)).And\
107
- (SCL.neq(9)).And\
108
- (SCL.neq(11))\
109
- .rename('QFmask');
110
- sentMasked = sentImg.select(['B8A','B12']).updateMask(QF_Mask); #B8 is another option- broadband NIR
111
- NBR = sentMasked.normalizedDifference(['B8A','B12']).toFloat().rename('NBR')
112
- return sentImg.addBands(NBR).addBands(QF_Mask).addBands(SCL)#.set('avgNBR', avgNBR)
113
-
114
- #createDates = NIFC_perims_716.aggregate_array('attr_Cre_1')
115
- #incidentIDs = NIFC_perims_716.aggregate_array('poly_Incid')
116
- #fireList = incidentIDs.getInfo()
117
- fireList = wildfire_names = [ "FRESNO JUNE LIGHTNING COMPLEX", "Larch Creek","Deadman","Cow Valley","0404 RV LONE ROCK",
118
- "PIONEER","South Fork", "Deer Springs","Basin","Lake","Horse Gulch","Falls","Silver King","Indios"]
119
- selected_fire = solara.reactive(fireList[6])
120
- dNBRvisParams = {'min': 0.0,'max': 0.8, 'palette': ['green', 'yellow','orange','red']}
121
- today = datetime.datetime.today().strftime('%Y-%m-%d')
122
-
123
- class Map(geemap.Map):
124
- def __init__(self, **kwargs):
125
- super().__init__(**kwargs)
126
- self.add_basemap('OpenStreetMap')
127
-
128
- self.customize_ee_data(selected_fire.value, today)
129
- self.add_selector()
130
- self.add_dwnldButton()
131
- self.add("layer_manager")
132
- self.remove("draw_control")
133
-
134
-
135
- def customize_ee_data(self, fireID, elapDays):
136
- NIFC_perims_716 = ee.FeatureCollection('projects/ovcrge-ssec-burn-scar-map-c116/assets/NIFC_perimeters_7-16')
137
- fire = NIFC_perims_716.filter(ee.Filter.eq('poly_Incid',fireID)).first()
138
- timestamp = fire.get('attr_Cre_1')
139
- geom = fire.geometry()
140
-
141
- startDate = ee.Date(timestamp)#.format('YYYY-MM-dd')
142
- endDate = ee.Date.parse('YYYY-MM-dd', str(today))
143
-
144
- boundingBox = ee.Geometry(geom.buffer(5000).bounds())
145
-
146
- elapDayNum = ee.Number(10)
147
- elapDay_plusOne = elapDayNum.add(ee.Number(1))
148
-
149
- def calc_nbr(pre_start, pre_stop, post_start, post_stop, bbox, goes):
150
-
151
- def MergeBands (eachImage):
152
- oneImage = ee.Image.cat(eachImage.get('CMI'), eachImage.get('FDC'))
153
- return oneImage
154
- displacementImg18 = ee.Image.load('projects/ee-losos/assets/G18-F-meter-offset_GEE')
155
- y_dif = displacementImg18.select([1])
156
- x_dif = displacementImg18.select([0]).multiply(-1)
157
- displacement18 = ee.Image([x_dif, y_dif])
158
-
159
- displacementImg16 = ee.Image.load('projects/ee-losos/assets/G16-F-meter-offset_GEE')
160
- y_dif = displacementImg16.select([1])
161
- x_dif = displacementImg16.select([0]).multiply(-1)
162
- displacement16 = ee.Image([x_dif, y_dif]);
163
-
164
- preCMIcol = ee.ImageCollection(f"NOAA/GOES/{goes}/MCMIPF").filter(ee.Filter.date(pre_start, pre_stop))\
165
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
166
- preFDCcol = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(pre_start, pre_stop))\
167
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
168
- postCMIcol = ee.ImageCollection(f"NOAA/GOES/{goes}/MCMIPF").filter(ee.Filter.date(post_start, post_stop))\
169
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
170
- postFDCcol = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(post_start, post_stop))\
171
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
172
-
173
- prejoinedGOES = ee.Join.inner('CMI','FDC').apply(
174
- primary = preCMIcol,
175
- secondary = preFDCcol,
176
- condition = ee.Filter.maxDifference(
177
- difference = 10, #milliseconds
178
- leftField = 'system:time_start',
179
- rightField = 'system:time_start',))
180
- preMiddayGOEScol = ee.ImageCollection(prejoinedGOES.map(lambda object: MergeBands(object)))
181
- preMiddayGOEScol = preMiddayGOEScol.map(GcalcCCsingle)
182
- pre_meanNBR = preMiddayGOEScol.select(['NBR']).mean()
183
- pre_meanNBR = pre_meanNBR.multiply(1.18).subtract(0.12)
184
-
185
- postjoinedGOES = ee.Join.inner('CMI','FDC').apply(
186
- primary = postCMIcol,
187
- secondary = postFDCcol,
188
- condition = ee.Filter.maxDifference(
189
- difference = 10, #milliseconds
190
- leftField = 'system:time_start',
191
- rightField = 'system:time_start',))
192
- postMiddayGOEScol = ee.ImageCollection(postjoinedGOES.map(lambda object: MergeBands(object)))
193
- postMiddayGOEScol = postMiddayGOEScol.map(GcalcCCsingle)
194
- post_meanNBR = postMiddayGOEScol.select(['NBR']).mean()
195
- post_meanNBR = post_meanNBR.multiply(1.18).subtract(0.12)
196
-
197
- dNBR_goes17 = pre_meanNBR.subtract(post_meanNBR).select('NBR')
198
-
199
-
200
- #GOES-16
201
- preCMIcol = ee.ImageCollection("NOAA/GOES/16/MCMIPF").filter(ee.Filter.date(pre_start, pre_stop))\
202
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
203
- preFDCcol = ee.ImageCollection("NOAA/GOES/16/FDCF").filter(ee.Filter.date(pre_start, pre_stop))\
204
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
205
-
206
- prejoinedGOES = ee.Join.inner('CMI','FDC').apply(
207
- primary = preCMIcol,
208
- secondary = preFDCcol,
209
- condition = ee.Filter.maxDifference(
210
- difference = 10, #milliseconds
211
- leftField = 'system:time_start',
212
- rightField = 'system:time_start',))
213
- preMiddayGOEScol = ee.ImageCollection(prejoinedGOES.map(lambda object: MergeBands(object)))
214
- preMiddayGOEScol = preMiddayGOEScol.map(GcalcCCsingle)
215
- pre_meanNBR = preMiddayGOEScol.select(['NBR']).mean()
216
- pre_meanNBR = pre_meanNBR.multiply(1.18).subtract(0.12)
217
-
218
-
219
- postCMIcol = ee.ImageCollection("NOAA/GOES/16/MCMIPF").filter(ee.Filter.date(post_start, post_stop))\
220
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
221
- postFDCcol = ee.ImageCollection("NOAA/GOES/16/FDCF").filter(ee.Filter.date(post_start, post_stop))\
222
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
223
-
224
- postjoinedGOES = ee.Join.inner('CMI','FDC').apply(
225
- primary = postCMIcol,
226
- secondary = postFDCcol,
227
- condition = ee.Filter.maxDifference(
228
- difference = 10, #milliseconds
229
- leftField = 'system:time_start',
230
- rightField = 'system:time_start',))
231
- postMiddayGOEScol = ee.ImageCollection(postjoinedGOES.map(lambda object: MergeBands(object)))
232
- postMiddayGOEScol = postMiddayGOEScol.map(GcalcCCsingle)
233
- post_meanNBR = postMiddayGOEScol.select(['NBR']).mean()
234
- post_meanNBR = post_meanNBR.multiply(1.18).subtract(0.12)
235
-
236
- dNBR_goes16 = pre_meanNBR.subtract(post_meanNBR).select('NBR')
237
-
238
- dNBRclip_goes17= dNBR_goes17.clip(bbox)
239
- dNBRclip_goes16= dNBR_goes16.clip(bbox)
240
- dNBRdisp_goes17 = dNBRclip_goes17.displace(displacement18, 'bicubic')
241
- dNBRdisp_goes16 = dNBRclip_goes16.displace(displacement16, 'bicubic')
242
- dNBRgoes_compos = ee.ImageCollection([dNBRdisp_goes17,dNBRdisp_goes16]).mean()
243
-
244
- #ACTIVE fire
245
- activeFire18 = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(pre_stop, post_stop))
246
- activeFire16 = ee.ImageCollection(f"NOAA/GOES/16/FDCF").filter(ee.Filter.date(pre_stop, post_stop))
247
- sumFRP18 = activeFire18.select('Power').sum().rename('sumFRP')
248
- sumFRP16 = activeFire16.select('Power').sum().rename('sumFRP')
249
- maskNoFire18 = sumFRP18.gt(200).displace(displacement18, 'bicubic')
250
- maskNoFire16 = sumFRP16.gt(200).displace(displacement16, 'bicubic')
251
- maskNoFire = ee.ImageCollection([maskNoFire18,maskNoFire16]).sum().gt(0)
252
-
253
- '''
254
- activeSNPP = ee.ImageCollection("NASA/LANCE/SNPP_VIIRS/C2").filter(ee.Filter.date(pre_stop, post_stop))
255
- activeNOAA20 = ee.ImageCollection("NASA/LANCE/NOAA20_VIIRS/C2").filter(ee.Filter.date(pre_stop, post_stop))
256
- sumFRP_SNPP = activeSNPP.select('confidence').max().rename('sumFRP')
257
- sumFRP_NOAA20 = activeNOAA20.select('confidence').max().rename('sumFRP')
258
- #maskNoFire = ee.ImageCollection([sumFRP_SNPP,sumFRP_NOAA20]).sum().gt(0)
259
- maskNoFire = sumFRP_SNPP.gt(0)
260
- '''
261
-
262
- #VIIRS
263
- preVIIRSimg = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(pre_start, pre_stop)).mean()
264
- postVIIRSimgCol = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(post_start, post_stop)) #TO FIX ON JUNE 18 sfork_startDate.advance(24, 'day'), sfork_startDate.advance(25,'day')
265
-
266
- #Landsat
267
- prelandsat8col = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
268
- postlandsat8col = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").filterDate(post_start, post_stop).filterBounds(bbox)
269
- prelandsat9col = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
270
- postlandsat9col = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2").filterDate(post_start, post_stop).filterBounds(bbox)
271
- prelandsatcol = prelandsat8col.merge(prelandsat9col)
272
- postlandsatcol = postlandsat8col.merge(postlandsat9col)
273
-
274
- #Sentinel
275
- presentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
276
- postsentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(post_start, post_stop).filterBounds(bbox) #TO FIX on JULY 5: sfork_startDate.advance(32, 'day'), sfork_startDate.advance(33,'day')
277
- #olderPostSentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(sfork_startDate.advance(37, 'day'), sfork_startDate.advance(38,'day')).filterBounds(bbox)
278
-
279
- #SAR
280
- #SARimg = ee.Image('projects/ovcrge-ssec-burn-scar-map-c116/assets/burned_20200907_20200919_test')
281
- #SARmask = SARimg.eq(1)
282
-
283
- if postVIIRSimgCol.size().getInfo() > 0:
284
- postVIIRSimg = postVIIRSimgCol.mean()
285
- preVIIRSimg = VcalcNBR(preVIIRSimg)
286
- postVIIRSimg = VcalcNBR(postVIIRSimg)
287
- dNBR_viirs = preVIIRSimg.subtract(postVIIRSimg).select('NBR')
288
- dNBRclip_viirs = dNBR_viirs.clip(bbox)
289
- else:
290
- dNBR_composite = dNBRgoes_compos
291
- if postsentCol.size().getInfo() > 0:
292
- presentMean = presentCol.mean()
293
- postsentMean = postsentCol.mean()
294
- presentImg = ScalcNBR(presentMean)
295
- postsentImg = ScalcNBR(postsentMean)
296
- dnbr_sent = presentImg.subtract(postsentImg).multiply(1.3).add(0.05).select('NBR')
297
- dNBRclip_sent = dnbr_sent.clip(bbox)
298
- dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_sent]).mosaic() #dNBRclip_viirs SHOULD GO IN IF UP TO DATE
299
- elif postlandsatcol.size().getInfo() > 0:
300
- prelandsat = prelandsatcol.mean()
301
- prelandsatImg = LcalcNBR(prelandsat)
302
- postlandsat = postlandsatcol.mean()
303
- postlandsatImg = LcalcNBR(postlandsat)
304
- dNBR_landsat = prelandsatImg.subtract(postlandsatImg).multiply(3.23).add(0.01).select('NBR')
305
- dNBRclip_ls = dNBR_landsat.clip(bbox)
306
- dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_ls]).mosaic() #dNBRclip_viirs SHOULD GO IN IF UP TO DATE
307
- else:
308
- dNBR_composite = ee.ImageCollection([dNBRgoes_compos]).mosaic() #dNBRclip_viirs SHOULD GO IN IF UP TO DATE
309
-
310
- masked_compos = dNBR_composite.updateMask(maskNoFire) #(SARmask)
311
- #doubleMasked_compos = masked_compos.updateMask(maskNoFire)
312
- doubleMasked_compos = masked_compos.mask(masked_compos.mask()).float()
313
- downloadArgs = {'name': 'VIIRS_burnMap',
314
- 'crs': 'EPSG:4326',
315
- 'scale': 60,
316
- 'region': bbox}
317
- url = doubleMasked_compos.getDownloadURL(downloadArgs)
318
-
319
- print(url)
320
- noDataVal = -9999
321
- unmaskedImage = doubleMasked_compos.unmask(noDataVal, False)
322
-
323
- task = ee.batch.Export.image.toDrive(**{
324
- 'image': unmaskedImage,
325
- 'description': "Composite_burnMap6",
326
- 'folder': "Earth Engine Outputs",
327
- 'fileNamePrefix': "Composite_burnMap_noData_VIIRS_June18_espg3857_60m",
328
- 'region': bbox,
329
- 'crs': 'EPSG:3857',
330
- 'scale': 60,})
331
- task.start()
332
- return masked_compos
333
-
334
-
335
- self.clear_specific_layers()
336
-
337
- fireImg = calc_nbr(startDate.advance(-7, 'day'), startDate, endDate.advance(-3, 'day'), endDate, boundingBox, 18)
338
- self.addLayer(fireImg, dNBRvisParams, fireID, True)
339
- self.centerObject(boundingBox, 10)
340
- file = fireImg
341
-
342
-
343
- def clear_specific_layers(self):
344
- layers_to_keep = ['OpenStreetMap']
345
- layers = list(self.layers)
346
- for layer in layers:
347
- if layer.name not in layers_to_keep:
348
- self.remove_layer(layer)
349
-
350
-
351
- def add_selector(self):
352
- selector = widgets.Dropdown(options=fireList, value=fireList[6], description='Current wildfire :', style={'description_width': '125px'}, layout=widgets.Layout(width='400px'))
353
-
354
- def on_selector_change(change):
355
- if change['name'] == 'value':
356
- selected_fire.value = change['new']
357
- self.customize_ee_data(selected_fire.value, today)
358
-
359
- selector.observe(on_selector_change, names='value')
360
- self.add_widget(selector, position="topleft")
361
-
362
-
363
- def add_dwnldButton(self):
364
- button = widgets.Button(description='Export to Drive',icon='cloud-arrow-down')
365
-
366
- #def on_button_click(change, file):
367
- # if change['name'] == 'value':
368
- # selected_days.value = change['new']
369
- # self.download_ee_image(file, "trial_file.tif", scale=30)
370
- def on_button_click(b):
371
- # Get the currently selected fire and elapsed days
372
- fire = selected_fire.value
373
- elapDays = today
374
-
375
- # Customize the EE data and download the image
376
- file = self.customize_ee_data(fire, elapDays)
377
- #self.download_ee_image(file, f"{fire}_NBR_{elapDays}days.tif", scale=30)
378
-
379
- button.observe(on_button_click)
380
- self.add_widget(button, position="topleft")
381
-
382
-
383
-
384
- @solara.component
385
- def Page():
386
-
387
- with solara.Column(align="center"):
388
- markdown = """
389
- ## Current 2024 wildfires over 10,000 acres"""
390
- solara.Markdown(markdown)
391
-
392
- # Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
393
- with solara.Column(style={"isolation": "isolate"}):
394
- map_widget = Map.element(
395
- center=[39, -120.5],
396
- zoom=8,
397
- height="600px",
398
- toolbar_ctrl=False
399
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/pages/historical_fires.py DELETED
@@ -1,429 +0,0 @@
1
- import ee
2
- import geemap
3
- import solara
4
- import ipywidgets as widgets
5
- #from NBR_calculations import GcalcNBR, VcalcNBR, LcalcNBR, ScalcNBR, GcalcCCsingle
6
- import requests
7
-
8
- # Bit-masking
9
- BitMask_0 = 1 << 0
10
- BitMask_1 = 1 << 1
11
- BitMask_2 = 1 << 2
12
- BitMask_3 = 1 << 3
13
- BitMask_4 = 1 << 4
14
- BitMask_5 = 1 << 5
15
- BitMask_6 = 1 << 6
16
- BitMask_7 = 1 << 7
17
- BitMask_8 = 1 << 8
18
- BitMask_9 = 1 << 9
19
-
20
- def GcalcCCsingle (goesImg):
21
-
22
- fireDQF = goesImg.select('DQF').int()
23
- CMI_QF3 = goesImg.select('DQF_C03').int()
24
- CMI_QF6 = goesImg.select('DQF_C06').int()
25
-
26
- #Right now, cloud mask is excluding clouds and water; active fire, bad data and fire free are unmasked. NBR mask exlcudes fire
27
- F_Mask = fireDQF.eq(0)
28
- C_Mask = (fireDQF.lt(2).Or(fireDQF.gt(2))).rename('C_Mask')
29
- #.And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('C_Mask')
30
- QF_Mask = (fireDQF.eq(1).Or(fireDQF.gt(3)))\
31
- .And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('QFmask')
32
-
33
- GOESmasked = goesImg.select(['CMI_C03','CMI_C06']).updateMask(QF_Mask)
34
- NBRmasked = GOESmasked.normalizedDifference(['CMI_C03', 'CMI_C06']).toFloat().rename('NBR')
35
- cloudMasked = goesImg.select('CMI_C03').updateMask(C_Mask).toFloat().rename('CC')
36
- fireMasked = goesImg.select('CMI_C03').updateMask(F_Mask).toFloat().rename('FC')
37
-
38
- return goesImg.addBands([NBRmasked,cloudMasked, fireMasked,QF_Mask,C_Mask])
39
-
40
- '''Parameter Array Name Value Bit(s) = Value
41
- Sun Glint QF1 Surface Reflectance None 6-7 = 00
42
- Low Sun Mask QF1 Surface Reflectance High 5 = 0
43
- Day/Night QF1 Surface Reflectance Day 4 =0
44
- Cloud Detection QF1 Surface Reflectance Confident Clear 2-3 = 00 or Problably Clear 2-3 = 01
45
- Cloud Mask Quality QF1 Surface Reflectance High or Medium 0-1 = 10 or 11
46
- Snow/Ice QF2 Surface Reflectance No Snow or Ice 5 = 0
47
- Cloud Shadow QF2 Surface Reflectance No Cloud Shadow 3 = 0
48
- LandWater QF2 Surface Reflectance Land, Snow, Arctic, Antarctic or Greenland, Desert 0-2 = 011, 100, 101, 110, 111
49
- Thin Cirrus Flag QF7 Surface Reflectance No Thin Cirrus 4 = 0
50
- Aerosol Quantity QF7 Surface Reflectance Climatology, Low or Medium 2-3 = 00, 01 or 10
51
- Adjacent to Cloud QF7 Surface Reflectance Not Adjacent to Cloud 1 = 0'''
52
-
53
- def VcalcNBR (VIIRSimg):
54
-
55
- QF1 = VIIRSimg.select('QF1').int()
56
- QF2 = VIIRSimg.select('QF2').int()
57
- QF7 = VIIRSimg.select('QF7').int()
58
-
59
- QF_Mask = (QF1.bitwiseAnd(BitMask_3).eq(0)).And\
60
- ((QF2.bitwiseAnd(BitMask_2).eq(4)).Or((QF2.bitwiseAnd(BitMask_1).eq(0)))).And\
61
- (QF2.bitwiseAnd(BitMask_5).eq(0)).rename('QFmask');
62
-
63
- VIIRSm = VIIRSimg.select(['I2','M11']).updateMask(QF_Mask);
64
- NBR = VIIRSm.normalizedDifference(['I2','M11']).toFloat().rename('NBR')
65
- return VIIRSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)
66
-
67
- ''' Bit 1: Dilated Cloud
68
- Bit 2: Cirrus (high confidence)
69
- Bit 3: Cloud
70
- Bit 4: Cloud Shadow
71
- Bit 5: Snow
72
- Bit 6: Clear (0: Cloud or Dilated Cloud bits are set, 1: Cloud and Dilated Cloud bits are not set)
73
- Bit 7: Water
74
- Bits 8-9: Cloud Confidence (0: None, 1: Low, 2: Medium, 3: High)
75
- Bits 10-11: Cloud Shadow Confidence (0: None, 1: Low, 2: Medium, 3: High)
76
- Bits 12-13: Snow/Ice Confidence (0: None, 1: Low, 2: Medium, 3: High)
77
- Bits 14-15: Cirrus Confidence (0: None, 1: Low, 2: Medium, 3: High)'''
78
-
79
- def LcalcNBR (LSimg):
80
- QApixel = LSimg.select('QA_PIXEL').int()
81
- QF_Mask =(QApixel.bitwiseAnd(BitMask_3).eq(0)).And\
82
- (QApixel.bitwiseAnd(BitMask_5).eq(0)).And\
83
- (QApixel.bitwiseAnd(BitMask_7).eq(0)).rename('QFmask');
84
-
85
- LSmasked = LSimg.select(['SR_B5','SR_B7']).updateMask(QF_Mask);
86
- NBR = LSmasked.normalizedDifference(['SR_B5','SR_B7']).toFloat().rename('NBR')
87
- return LSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)
88
-
89
- ''' 1 Saturated or defective
90
- 2 Dark Area Pixels
91
- 3 Cloud Shadows
92
- 4 Vegetation
93
- 5 Bare Soils
94
- 6 Water
95
- 7 Clouds Low Probability / Unclassified
96
- 8 Clouds Medium Probability
97
- 9 Clouds High Probability
98
- 10 Cirrus
99
- 11 Snow / Ice'''
100
-
101
- def ScalcNBR (sentImg):
102
- SCL = sentImg.select('SCL');
103
- QF_Mask =(SCL.neq(6)).And\
104
- (SCL.neq(8)).And\
105
- (SCL.neq(9)).And\
106
- (SCL.neq(11))\
107
- .rename('QFmask');
108
- sentMasked = sentImg.select(['B8A','B12']).updateMask(QF_Mask); #B8 is another option- broadband NIR
109
- NBR = sentMasked.normalizedDifference(['B8A','B12']).toFloat().rename('NBR')
110
- return sentImg.addBands(NBR).addBands(QF_Mask).addBands(SCL)#.set('avgNBR', avgNBR)
111
-
112
-
113
- fireList = ["North Complex", "Dixie", "Cameron Peak", "August Complex", "South Fork"]
114
- selected_fire = solara.reactive(fireList[4])
115
- selected_days = solara.reactive(25) #30
116
- dNBRvisParams = {'min': 0.0,'max': 0.8, 'palette': ['green', 'yellow','orange','red']}
117
-
118
-
119
- class Map(geemap.Map):
120
- def __init__(self, **kwargs):
121
- super().__init__(**kwargs)
122
- self.add_basemap('OpenStreetMap')
123
- self.customize_ee_data(selected_fire.value, selected_days.value)
124
- self.add_selector()
125
- self.add_intSlider()
126
- self.add_dwnldButton()
127
- self.add("layer_manager")
128
- self.remove("draw_control")
129
-
130
-
131
- def customize_ee_data(self, fire, elapDays):
132
- elapDayNum = ee.Number(elapDays)
133
- elapDay_plusOne = elapDayNum.add(ee.Number(1))
134
-
135
- north_startDate = ee.Date('2020-08-16')
136
- dixie_startDate = ee.Date('2021-07-13')
137
- cam_startDate = ee.Date('2020-08-13')
138
- aug_startDate = ee.Date('2020-08-15')
139
- sfork_startDate = ee.Date('2024-05-25')
140
-
141
- north_complex_bb = ee.Geometry.BBox(-121.616097, 39.426723, -120.668526, 40.030845)
142
- dixie_bb = ee.Geometry.BBox(-121.680467, 39.759303, -120.065477, 40.873387)
143
- cam_peak_bb = ee.Geometry.BBox(-106.014784, 40.377907, -105.116651, 40.822094)
144
- aug_complex_bb = ee.Geometry.BBox(-123.668726, 39.337654, -122.355860, 40.498304)
145
- sfork_bb = ee.Geometry.BBox(-106.192, 33.1, -105.065, 33.782)
146
-
147
- def calc_nbr(pre_start, pre_stop, post_start, post_stop, bbox, goes):
148
- def MergeBands (eachImage):
149
- oneImage = ee.Image.cat(eachImage.get('CMI'), eachImage.get('FDC'))
150
- return oneImage
151
- displacementImg18 = ee.Image.load('projects/ee-losos/assets/G18-F-meter-offset_GEE')
152
- y_dif = displacementImg18.select([1])
153
- x_dif = displacementImg18.select([0]).multiply(-1)
154
- displacement18 = ee.Image([x_dif, y_dif])
155
-
156
- displacementImg16 = ee.Image.load('projects/ee-losos/assets/G16-F-meter-offset_GEE')
157
- y_dif = displacementImg16.select([1])
158
- x_dif = displacementImg16.select([0]).multiply(-1)
159
- displacement16 = ee.Image([x_dif, y_dif]);
160
-
161
- preCMIcol = ee.ImageCollection(f"NOAA/GOES/{goes}/MCMIPF").filter(ee.Filter.date(pre_start, pre_stop))\
162
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
163
- preFDCcol = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(pre_start, pre_stop))\
164
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
165
- postCMIcol = ee.ImageCollection(f"NOAA/GOES/{goes}/MCMIPF").filter(ee.Filter.date(post_start, post_stop))\
166
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
167
- postFDCcol = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(post_start, post_stop))\
168
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
169
-
170
- prejoinedGOES = ee.Join.inner('CMI','FDC').apply(
171
- primary = preCMIcol,
172
- secondary = preFDCcol,
173
- condition = ee.Filter.maxDifference(
174
- difference = 10, #milliseconds
175
- leftField = 'system:time_start',
176
- rightField = 'system:time_start',))
177
- preMiddayGOEScol = ee.ImageCollection(prejoinedGOES.map(lambda object: MergeBands(object)))
178
- preMiddayGOEScol = preMiddayGOEScol.map(GcalcCCsingle)
179
- pre_meanNBR = preMiddayGOEScol.select(['NBR']).mean()
180
- pre_meanNBR = pre_meanNBR.multiply(1.18).subtract(0.12)
181
-
182
- postjoinedGOES = ee.Join.inner('CMI','FDC').apply(
183
- primary = postCMIcol,
184
- secondary = postFDCcol,
185
- condition = ee.Filter.maxDifference(
186
- difference = 10, #milliseconds
187
- leftField = 'system:time_start',
188
- rightField = 'system:time_start',))
189
- postMiddayGOEScol = ee.ImageCollection(postjoinedGOES.map(lambda object: MergeBands(object)))
190
- postMiddayGOEScol = postMiddayGOEScol.map(GcalcCCsingle)
191
- post_meanNBR = postMiddayGOEScol.select(['NBR']).mean()
192
- post_meanNBR = post_meanNBR.multiply(1.18).subtract(0.12)
193
-
194
- dNBR_goes17 = pre_meanNBR.subtract(post_meanNBR).select('NBR')
195
-
196
-
197
- #GOES-16
198
- preCMIcol = ee.ImageCollection("NOAA/GOES/16/MCMIPF").filter(ee.Filter.date(pre_start, pre_stop))\
199
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
200
- preFDCcol = ee.ImageCollection("NOAA/GOES/16/FDCF").filter(ee.Filter.date(pre_start, pre_stop))\
201
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
202
-
203
- prejoinedGOES = ee.Join.inner('CMI','FDC').apply(
204
- primary = preCMIcol,
205
- secondary = preFDCcol,
206
- condition = ee.Filter.maxDifference(
207
- difference = 10, #milliseconds
208
- leftField = 'system:time_start',
209
- rightField = 'system:time_start',))
210
- preMiddayGOEScol = ee.ImageCollection(prejoinedGOES.map(lambda object: MergeBands(object)))
211
- preMiddayGOEScol = preMiddayGOEScol.map(GcalcCCsingle)
212
- pre_meanNBR = preMiddayGOEScol.select(['NBR']).mean()
213
- pre_meanNBR = pre_meanNBR.multiply(1.18).subtract(0.12)
214
-
215
-
216
- postCMIcol = ee.ImageCollection("NOAA/GOES/16/MCMIPF").filter(ee.Filter.date(post_start, post_stop))\
217
- .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
218
- postFDCcol = ee.ImageCollection("NOAA/GOES/16/FDCF").filter(ee.Filter.date(post_start, post_stop))\
219
- .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
220
-
221
- postjoinedGOES = ee.Join.inner('CMI','FDC').apply(
222
- primary = postCMIcol,
223
- secondary = postFDCcol,
224
- condition = ee.Filter.maxDifference(
225
- difference = 10, #milliseconds
226
- leftField = 'system:time_start',
227
- rightField = 'system:time_start',))
228
- postMiddayGOEScol = ee.ImageCollection(postjoinedGOES.map(lambda object: MergeBands(object)))
229
- postMiddayGOEScol = postMiddayGOEScol.map(GcalcCCsingle)
230
- post_meanNBR = postMiddayGOEScol.select(['NBR']).mean()
231
- post_meanNBR = post_meanNBR.multiply(1.18).subtract(0.12)
232
-
233
- dNBR_goes16 = pre_meanNBR.subtract(post_meanNBR).select('NBR')
234
-
235
- dNBRclip_goes17= dNBR_goes17.clip(bbox)
236
- dNBRclip_goes16= dNBR_goes16.clip(bbox)
237
- dNBRdisp_goes17 = dNBRclip_goes17.displace(displacement18, 'bicubic')
238
- dNBRdisp_goes16 = dNBRclip_goes16.displace(displacement16, 'bicubic')
239
- dNBRgoes_compos = ee.ImageCollection([dNBRdisp_goes17,dNBRdisp_goes16]).mean()
240
-
241
- #ACTIVE fire
242
- activeFire18 = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(pre_stop, post_stop))
243
- activeFire16 = ee.ImageCollection(f"NOAA/GOES/16/FDCF").filter(ee.Filter.date(pre_stop, post_stop))
244
- sumFRP18 = activeFire18.select('Power').sum().rename('sumFRP')
245
- sumFRP16 = activeFire16.select('Power').sum().rename('sumFRP')
246
- maskNoFire18 = sumFRP18.gt(200).displace(displacement18, 'bicubic')
247
- maskNoFire16 = sumFRP16.gt(200).displace(displacement16, 'bicubic')
248
- maskNoFire = ee.ImageCollection([maskNoFire18,maskNoFire16]).sum().gt(0)
249
-
250
- '''
251
- activeSNPP = ee.ImageCollection("NASA/LANCE/SNPP_VIIRS/C2").filter(ee.Filter.date(pre_stop, post_stop))
252
- activeNOAA20 = ee.ImageCollection("NASA/LANCE/NOAA20_VIIRS/C2").filter(ee.Filter.date(pre_stop, post_stop))
253
- sumFRP_SNPP = activeSNPP.select('confidence').max().rename('sumFRP')
254
- sumFRP_NOAA20 = activeNOAA20.select('confidence').max().rename('sumFRP')
255
- #maskNoFire = ee.ImageCollection([sumFRP_SNPP,sumFRP_NOAA20]).sum().gt(0)
256
- maskNoFire = sumFRP_SNPP.gt(0)
257
- '''
258
-
259
- #VIIRS
260
- preVIIRSimg = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(pre_start, pre_stop)).mean()
261
- #postVIIRSimgCol = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(post_start, post_stop))
262
- postVIIRSimgCol = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(post_start, post_stop)) #TO FIX ON JUNE 18 sfork_startDate.advance(24, 'day'), sfork_startDate.advance(25,'day')
263
-
264
- #Landsat
265
- prelandsat8col = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
266
- postlandsat8col = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").filterDate(post_start, post_stop).filterBounds(bbox)
267
- prelandsat9col = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
268
- postlandsat9col = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2").filterDate(post_start, post_stop).filterBounds(bbox)
269
- prelandsatcol = prelandsat8col.merge(prelandsat9col)
270
- postlandsatcol = postlandsat8col.merge(postlandsat9col)
271
-
272
- #Sentinel
273
- presentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
274
- postsentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(post_start, post_stop).filterBounds(bbox) #TO FIX on JULY 5: sfork_startDate.advance(32, 'day'), sfork_startDate.advance(33,'day')
275
- olderPostSentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(sfork_startDate.advance(37, 'day'), sfork_startDate.advance(38,'day')).filterBounds(bbox)
276
- #SAR
277
- #SARimg = ee.Image('projects/ovcrge-ssec-burn-scar-map-c116/assets/burned_20200907_20200919_test')
278
- #SARmask = SARimg.eq(1)
279
- if postVIIRSimgCol.size().getInfo() > 0:
280
- postVIIRSimg = postVIIRSimgCol.mean()
281
- preVIIRSimg = VcalcNBR(preVIIRSimg)
282
- postVIIRSimg = VcalcNBR(postVIIRSimg)
283
- dNBR_viirs = preVIIRSimg.subtract(postVIIRSimg).select('NBR')
284
- dNBRclip_viirs = dNBR_viirs.clip(bbox)
285
- else:
286
- dNBR_composite = dNBRgoes_compos
287
- if postsentCol.size().getInfo() > 0:
288
- presentMean = presentCol.mean()
289
- postsentMean = postsentCol.mean()
290
- postsent2Mean = olderPostSentCol.mean()
291
- presentImg = ScalcNBR(presentMean)
292
- postsentImg = ScalcNBR(postsentMean)
293
- postsentImg2 = ScalcNBR(postsent2Mean)
294
- postSentCombo = ee.ImageCollection([postsentImg,postsentImg2]).mosaic()
295
- dnbr_sent = presentImg.subtract(postSentCombo).multiply(1.3).add(0.05).select('NBR')
296
- dNBRclip_sent = dnbr_sent.clip(bbox)
297
- dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_viirs,dNBRclip_sent]).mosaic()
298
- elif postlandsatcol.size().getInfo() > 0:
299
- print(postlandsatcol.size().getInfo())
300
- prelandsat = prelandsatcol.mean()
301
- prelandsatImg = LcalcNBR(prelandsat)
302
- postlandsat = postlandsatcol.mean()
303
- postlandsatImg = LcalcNBR(postlandsat)
304
- dNBR_landsat = prelandsatImg.subtract(postlandsatImg).multiply(3.23).add(0.01).select('NBR')
305
- dNBRclip_ls = dNBR_landsat.clip(bbox)
306
- dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_viirs,dNBRclip_ls]).mosaic()
307
- else:
308
- dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_viirs]).mosaic()
309
-
310
- masked_compos = dNBR_composite.updateMask(maskNoFire) #(SARmask)
311
- #doubleMasked_compos = masked_compos.updateMask(maskNoFire)
312
- doubleMasked_compos = masked_compos.mask(masked_compos.mask()).float()
313
- downloadArgs = {'name': 'VIIRS_burnMap',
314
- 'crs': 'EPSG:4326',
315
- 'scale': 60,
316
- 'region': bbox}
317
- url = doubleMasked_compos.getDownloadURL(downloadArgs)
318
-
319
- print(url)
320
- noDataVal = -9999
321
- unmaskedImage = doubleMasked_compos.unmask(noDataVal, False)
322
-
323
- task = ee.batch.Export.image.toDrive(**{
324
- 'image': unmaskedImage,
325
- 'description': "Composite_burnMap6",
326
- 'folder': "Earth Engine Outputs",
327
- 'fileNamePrefix': "Composite_burnMap_noData_VIIRS_June18_espg3857_60m",
328
- 'region': bbox,
329
- 'crs': 'EPSG:3857',
330
- 'scale': 60,})
331
- #task.start()
332
- return masked_compos
333
-
334
-
335
- self.clear_specific_layers()
336
-
337
- if fire == "North Complex":
338
- north_complex = calc_nbr(north_startDate.advance(-7, 'day'), north_startDate, north_startDate.advance(elapDayNum, 'day'), north_startDate.advance(elapDay_plusOne,'day'), north_complex_bb, 17)
339
- self.addLayer(north_complex, dNBRvisParams, 'North Complex GOES NBR', True)
340
- self.centerObject(north_complex_bb, 9)
341
- file = north_complex
342
- elif fire == "Dixie":
343
- dixie = calc_nbr(dixie_startDate.advance(-7, 'day'), dixie_startDate, dixie_startDate.advance(elapDayNum, 'day'), dixie_startDate.advance(elapDay_plusOne,'day'), dixie_bb, 17)
344
- self.addLayer(dixie, dNBRvisParams, 'Dixie Complex GOES NBR', True)
345
- self.centerObject(dixie_bb, 9)
346
- file = dixie
347
- elif fire == "Cameron Peak":
348
- cam_peak = calc_nbr(cam_startDate.advance(-7, 'day'), cam_startDate, cam_startDate.advance(elapDayNum, 'day'), cam_startDate.advance(elapDay_plusOne,'day'), cam_peak_bb, 17)
349
- self.addLayer(cam_peak, dNBRvisParams, 'Cameron Peak GOES NBR', True)
350
- self.centerObject(cam_peak_bb, 9)
351
- file = cam_peak
352
- elif fire == "August Complex":
353
- aug_complex = calc_nbr(aug_startDate.advance(-7, 'day'), aug_startDate, aug_startDate.advance(elapDayNum, 'day'), aug_startDate.advance(elapDay_plusOne,'day'), aug_complex_bb, 17)
354
- self.addLayer(aug_complex, dNBRvisParams, 'August Complex GOES NBR', True)
355
- self.centerObject(aug_complex_bb, 9)
356
- file = aug_complex
357
- elif fire == "South Fork":
358
- sfork = calc_nbr(sfork_startDate.advance(-7, 'day'), sfork_startDate, sfork_startDate.advance(elapDayNum, 'day'), sfork_startDate.advance(elapDay_plusOne,'day'), sfork_bb, 18)
359
- self.addLayer(sfork, dNBRvisParams, 'South Fork GOES NBR', True)
360
- self.centerObject(sfork_bb, 9)
361
- file = sfork
362
-
363
- def clear_specific_layers(self):
364
- layers_to_keep = ['OpenStreetMap']
365
- layers = list(self.layers)
366
- for layer in layers:
367
- if layer.name not in layers_to_keep:
368
- self.remove_layer(layer)
369
-
370
-
371
- def add_selector(self):
372
- selector = widgets.Dropdown(options=fireList, value="South Fork", description='Wildfire Case Study:', style={'description_width': '125px'}, layout=widgets.Layout(width='400px'))
373
-
374
- def on_selector_change(change):
375
- if change['name'] == 'value':
376
- selected_fire.value = change['new']
377
- self.customize_ee_data(selected_fire.value, selected_days.value)
378
-
379
- selector.observe(on_selector_change, names='value')
380
- self.add_widget(selector, position="topleft")
381
-
382
- def add_intSlider(self):
383
- slider = widgets.IntSlider(value=selected_days.value,min=1,max=40,step=1,description='Elapsed days:',style={'description_width': '125px'}, layout=widgets.Layout(width='400px'))
384
-
385
- def on_slider_change(change):
386
- if change['name'] == 'value':
387
- selected_days.value = change['new']
388
- self.customize_ee_data(selected_fire.value, selected_days.value)
389
-
390
- slider.observe(on_slider_change, names='value')
391
- self.add_widget(slider, position="topleft")
392
-
393
- def add_dwnldButton(self):
394
- button = widgets.Button(description='Download',icon='cloud-arrow-down')
395
-
396
- #def on_button_click(change, file):
397
- # if change['name'] == 'value':
398
- # selected_days.value = change['new']
399
- # self.download_ee_image(file, "trial_file.tif", scale=30)
400
- def on_button_click(b):
401
- # Get the currently selected fire and elapsed days
402
- fire = selected_fire.value
403
- elapDays = selected_days.value
404
-
405
- # Customize the EE data and download the image
406
- file = self.customize_ee_data(fire, elapDays)
407
- #self.download_ee_image(file, f"{fire}_NBR_{elapDays}days.tif", scale=30)
408
-
409
- button.observe(on_button_click)
410
- self.add_widget(button, position="topleft")
411
-
412
-
413
-
414
- @solara.component
415
- def Page():
416
-
417
- with solara.Column(align="center"):
418
- markdown = """
419
- ## Historical Western US wildfires from 2020-2021 """
420
- solara.Markdown(markdown)
421
-
422
- # Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
423
- with solara.Column(style={"isolation": "isolate"}):
424
- map_widget = Map.element(
425
- center=[39, -120.5],
426
- zoom=8,
427
- height="600px",
428
- toolbar_ctrl=False
429
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/requirements.txt DELETED
@@ -1,6 +0,0 @@
1
- geemap
2
- solara== 1.33.0
3
- geopandas
4
- pydantic< 2.0
5
- ipyevents
6
- ipywidgets
 
 
 
 
 
 
 
burn_mapper/utils/NBR_calculations.py DELETED
@@ -1,130 +0,0 @@
1
- import ee
2
-
3
- ''' 0 Good quality fire
4
- 1 Good quality fire-free land
5
- 2 Invalid due to opaque cloud
6
- 3 Invalid due to surface type or sunglint or LZA threshold exceeded or off earth or missing input data
7
- 4 Invalid due to bad input data
8
- 5 Invalid due to algorithm failure'''
9
- # Bit-masking
10
- BitMask_0 = 1 << 0
11
- BitMask_1 = 1 << 1
12
- BitMask_2 = 1 << 2
13
- BitMask_3 = 1 << 3
14
- BitMask_4 = 1 << 4
15
- BitMask_5 = 1 << 5
16
- BitMask_6 = 1 << 6
17
- BitMask_7 = 1 << 7
18
- BitMask_8 = 1 << 8
19
- BitMask_9 = 1 << 9
20
-
21
- def GcalcNBR (goesImg, aoi):
22
- #day = ee.Date(eachImg.get('system:time_start')).get('day','America/Los_Angeles')
23
- fireMode = goesImg.select('fireMode')
24
- fireMin = goesImg.select('fireMin')
25
-
26
- CMI_QF3 = goesImg.select('DQF_C03').int()
27
- CMI_QF6 = goesImg.select('DQF_C06').int()
28
-
29
- # To include active fire pixels - fireMin.lt(2)\ for next line
30
- QF_Mask = (fireMin.eq(1)\
31
- .Or(fireMin.gt(3)))\
32
- .And(CMI_QF3.lt(2))\
33
- .And(CMI_QF6.lt(2))\
34
- .rename('QFmask');
35
- GOESm = goesImg.select(['CMI_C03','CMI_C06']).updateMask(QF_Mask)
36
- NBR = GOESm.normalizedDifference(['CMI_C03', 'CMI_C06']).toFloat().rename('NBR')
37
-
38
- return goesImg.addBands([NBR,QF_Mask])
39
-
40
- def GcalcCCsingle (goesImg):
41
-
42
- fireDQF = goesImg.select('DQF').int()
43
- CMI_QF3 = goesImg.select('DQF_C03').int()
44
- CMI_QF6 = goesImg.select('DQF_C06').int()
45
-
46
- #Right now, cloud mask is excluding clouds and water; active fire, bad data and fire free are unmasked. NBR mask exlcudes fire
47
- F_Mask = fireDQF.eq(0)
48
- C_Mask = (fireDQF.lt(2).Or(fireDQF.gt(2))).rename('C_Mask')
49
- #.And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('C_Mask')
50
- QF_Mask = (fireDQF.eq(1).Or(fireDQF.gt(3)))\
51
- .And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('QFmask')
52
-
53
- GOESmasked = goesImg.select(['CMI_C03','CMI_C06']).updateMask(QF_Mask)
54
- NBRmasked = GOESmasked.normalizedDifference(['CMI_C03', 'CMI_C06']).toFloat().rename('NBR')
55
- cloudMasked = goesImg.select('CMI_C03').updateMask(C_Mask).toFloat().rename('CC')
56
- fireMasked = goesImg.select('CMI_C03').updateMask(F_Mask).toFloat().rename('FC')
57
-
58
- return goesImg.addBands([NBRmasked,cloudMasked, fireMasked,QF_Mask,C_Mask])
59
-
60
- '''Parameter Array Name Value Bit(s) = Value
61
- Sun Glint QF1 Surface Reflectance None 6-7 = 00
62
- Low Sun Mask QF1 Surface Reflectance High 5 = 0
63
- Day/Night QF1 Surface Reflectance Day 4 =0
64
- Cloud Detection QF1 Surface Reflectance Confident Clear 2-3 = 00 or Problably Clear 2-3 = 01
65
- Cloud Mask Quality QF1 Surface Reflectance High or Medium 0-1 = 10 or 11
66
- Snow/Ice QF2 Surface Reflectance No Snow or Ice 5 = 0
67
- Cloud Shadow QF2 Surface Reflectance No Cloud Shadow 3 = 0
68
- LandWater QF2 Surface Reflectance Land, Snow, Arctic, Antarctic or Greenland, Desert 0-2 = 011, 100, 101, 110, 111
69
- Thin Cirrus Flag QF7 Surface Reflectance No Thin Cirrus 4 = 0
70
- Aerosol Quantity QF7 Surface Reflectance Climatology, Low or Medium 2-3 = 00, 01 or 10
71
- Adjacent to Cloud QF7 Surface Reflectance Not Adjacent to Cloud 1 = 0'''
72
-
73
- def VcalcNBR (VIIRSimg):
74
-
75
- QF1 = VIIRSimg.select('QF1').int()
76
- QF2 = VIIRSimg.select('QF2').int()
77
- QF7 = VIIRSimg.select('QF7').int()
78
-
79
- QF_Mask = (QF1.bitwiseAnd(BitMask_3).eq(0)).And\
80
- ((QF2.bitwiseAnd(BitMask_2).eq(4)).Or((QF2.bitwiseAnd(BitMask_1).eq(0)))).And\
81
- (QF2.bitwiseAnd(BitMask_5).eq(0)).rename('QFmask');
82
-
83
- VIIRSm = VIIRSimg.select(['I2','M11']).updateMask(QF_Mask);
84
- NBR = VIIRSm.normalizedDifference(['I2','M11']).toFloat().rename('NBR')
85
- return VIIRSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)
86
-
87
- ''' Bit 1: Dilated Cloud
88
- Bit 2: Cirrus (high confidence)
89
- Bit 3: Cloud
90
- Bit 4: Cloud Shadow
91
- Bit 5: Snow
92
- Bit 6: Clear (0: Cloud or Dilated Cloud bits are set, 1: Cloud and Dilated Cloud bits are not set)
93
- Bit 7: Water
94
- Bits 8-9: Cloud Confidence (0: None, 1: Low, 2: Medium, 3: High)
95
- Bits 10-11: Cloud Shadow Confidence (0: None, 1: Low, 2: Medium, 3: High)
96
- Bits 12-13: Snow/Ice Confidence (0: None, 1: Low, 2: Medium, 3: High)
97
- Bits 14-15: Cirrus Confidence (0: None, 1: Low, 2: Medium, 3: High)'''
98
-
99
- def LcalcNBR (LSimg):
100
- QApixel = LSimg.select('QA_PIXEL').int()
101
- QF_Mask =(QApixel.bitwiseAnd(BitMask_3).eq(0)).And\
102
- (QApixel.bitwiseAnd(BitMask_5).eq(0)).And\
103
- (QApixel.bitwiseAnd(BitMask_7).eq(0)).rename('QFmask');
104
-
105
- LSmasked = LSimg.select(['SR_B5','SR_B7']).updateMask(QF_Mask);
106
- NBR = LSmasked.normalizedDifference(['SR_B5','SR_B7']).toFloat().rename('NBR')
107
- return LSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)
108
-
109
- ''' 1 Saturated or defective
110
- 2 Dark Area Pixels
111
- 3 Cloud Shadows
112
- 4 Vegetation
113
- 5 Bare Soils
114
- 6 Water
115
- 7 Clouds Low Probability / Unclassified
116
- 8 Clouds Medium Probability
117
- 9 Clouds High Probability
118
- 10 Cirrus
119
- 11 Snow / Ice'''
120
-
121
- def ScalcNBR (sentImg):
122
- SCL = sentImg.select('SCL');
123
- QF_Mask =(SCL.neq(6)).And\
124
- (SCL.neq(8)).And\
125
- (SCL.neq(9)).And\
126
- (SCL.neq(11))\
127
- .rename('QFmask');
128
- sentMasked = sentImg.select(['B8A','B12']).updateMask(QF_Mask); #B8 is another option- broadband NIR
129
- NBR = sentMasked.normalizedDifference(['B8A','B12']).toFloat().rename('NBR')
130
- return sentImg.addBands(NBR).addBands(QF_Mask).addBands(SCL)#.set('avgNBR', avgNBR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
burn_mapper/utils/__init__.py DELETED
File without changes