<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://grasswiki.osgeo.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%E2%9A%A0%EF%B8%8FYchemin</id>
	<title>GRASS-Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://grasswiki.osgeo.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=%E2%9A%A0%EF%B8%8FYchemin"/>
	<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/wiki/Special:Contributions/%E2%9A%A0%EF%B8%8FYchemin"/>
	<updated>2026-05-25T19:45:14Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27354</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27354"/>
		<updated>2023-12-18T08:01:50Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. &lt;br /&gt;
&lt;br /&gt;
Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. &lt;br /&gt;
&lt;br /&gt;
The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. &lt;br /&gt;
&lt;br /&gt;
On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). &lt;br /&gt;
&lt;br /&gt;
The i.eb.* modules and models deal with:&lt;br /&gt;
* conduction {{cmd|i.eb.soilheatflux}} (for thermal conduction in soils)&lt;br /&gt;
* convection i.eb.h_* especially (for thermal convection in atmosphere)&lt;br /&gt;
* residual method estimating the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). &lt;br /&gt;
&lt;br /&gt;
Additionally, a helper module {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness, necessary in latent heat flux estimation.&lt;br /&gt;
&lt;br /&gt;
For a detailed theory and modelling information behind these modules, please read the following document: [[File:Evaporation_manual_v0.6.7.pdf]]&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000) Status: Incomplete Module&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002) Status: Incomplete Module&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=File:Evaporation_manual_v0.6.7.pdf&amp;diff=27353</id>
		<title>File:Evaporation manual v0.6.7.pdf</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=File:Evaporation_manual_v0.6.7.pdf&amp;diff=27353"/>
		<updated>2023-12-18T07:59:52Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: evapotranspiration modelling step by step manual&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
evapotranspiration modelling step by step manual&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27334</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27334"/>
		<updated>2023-12-02T12:15:37Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Signatures preparation and launching i.spec.sam */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]][[File:HyperionR50G35B100.png||100px]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Signatures preparation and launching i.spec.sam ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
# Define the Hyperion files available for processing&lt;br /&gt;
listf=&amp;quot;ref.8 ref.9 ref.10 ref.11 ref.12 ref.13 ref.14 ref.15 ref.16 ref.17 ref.18 ref.19 ref.20 ref.21 ref.22 ref.23 ref.24 ref.25 ref.26 ref.27 ref.28 ref.29 ref.30 ref.31 ref.32 ref.33 ref.34 ref.35 ref.36 ref.37 ref.38 ref.39 ref.40 ref.41 ref.42 ref.43 ref.44 ref.45 ref.46 ref.47 ref.48 ref.49 ref.50 ref.51 ref.52 ref.53 ref.54 ref.55 ref.56 ref.57 ref.77 ref.78 ref.79 ref.80 ref.81 ref.82 ref.83 ref.84 ref.85 ref.86 ref.87 ref.88 ref.89 ref.90 ref.91 ref.92 ref.93 ref.94 ref.95 ref.96 ref.97 ref.98 ref.99 ref.100 ref.101 ref.102 ref.103 ref.104 ref.105 ref.106 ref.107 ref.108 ref.109 ref.110 ref.111 ref.112 ref.113 ref.114 ref.115 ref.116 ref.117 ref.118 ref.119 ref.120 ref.121 ref.122 ref.123 ref.124 ref.125 ref.126 ref.127 ref.128 ref.129 ref.130 ref.131 ref.132 ref.133 ref.134 ref.135 ref.136 ref.137 ref.138 ref.139 ref.140 ref.141 ref.142 ref.143 ref.144 ref.145 ref.146 ref.147 ref.148 ref.149 ref.150 ref.151 ref.152 ref.153 ref.154 ref.155 ref.156 ref.157&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Clean up .sign files&lt;br /&gt;
rm -f *.sign&lt;br /&gt;
# Name the signature file for i.spec.sam&lt;br /&gt;
sigfname=&amp;quot;KL.sig&amp;quot;&lt;br /&gt;
rm -f $sigfname&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;# Signatures for Hyperion image of KL&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Water in river&lt;br /&gt;
classname=&amp;quot;water1&amp;quot;&lt;br /&gt;
coords=&amp;quot;215455.8579625377,383556.12608450593&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
# Define cols number in sig file&lt;br /&gt;
lno=$(cat temp | wc -l)&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
rm -f temp1&lt;br /&gt;
for number in $(cat temp)&lt;br /&gt;
do&lt;br /&gt;
    printf &amp;quot;%.8f &amp;quot; $number &amp;gt;&amp;gt; temp1&lt;br /&gt;
done&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp1 &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Forest area&lt;br /&gt;
classname=&amp;quot;forest1&amp;quot;&lt;br /&gt;
coords=&amp;quot;199906.1669829222,331418.4535104364&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
rm -f temp1&lt;br /&gt;
for number in $(cat temp)&lt;br /&gt;
do&lt;br /&gt;
    printf &amp;quot;%.8f &amp;quot; $number &amp;gt;&amp;gt; temp1&lt;br /&gt;
done&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp1 &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define rows number in sig file&lt;br /&gt;
signo=$(ls *.sign | wc -l)&lt;br /&gt;
&lt;br /&gt;
# Complete the sig file&lt;br /&gt;
echo &amp;quot;# &amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
echo &amp;quot;Matrix: $signo by $lno&amp;quot; &amp;gt;&amp;gt; $sigfname &lt;br /&gt;
n=0&lt;br /&gt;
for file in *.sign&lt;br /&gt;
do&lt;br /&gt;
    echo &amp;quot;row$n: $(cat $file)&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
    n=$(echo &amp;quot;$n + 1&amp;quot; | bc)&lt;br /&gt;
done&lt;br /&gt;
# i.spec.sam does not like a space at the end of a line&lt;br /&gt;
sed -i 's/\s*$//' $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define the imagery working group&lt;br /&gt;
listmaps=$(echo $listf | sed 's/\ /,/g')&lt;br /&gt;
i.group group=temp input=$listmaps --quiet&lt;br /&gt;
&lt;br /&gt;
# Run a first set of Spectral Angle convergence&lt;br /&gt;
i.spec.sam group=temp input=$sigfname result=s --verbose&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27333</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27333"/>
		<updated>2023-12-02T11:50:24Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Signatures preparation and launching i.spec.sam */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]][[File:HyperionR50G35B100.png||100px]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Signatures preparation and launching i.spec.sam ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
# Define the Hyperion files available for processing&lt;br /&gt;
listf=&amp;quot;ref.8 ref.9 ref.10 ref.11 ref.12 ref.13 ref.14 ref.15 ref.16 ref.17 ref.18 ref.19 ref.20 ref.21 ref.22 ref.23 ref.24 ref.25 ref.26 ref.27 ref.28 ref.29 ref.30 ref.31 ref.32 ref.33 ref.34 ref.35 ref.36 ref.37 ref.38 ref.39 ref.40 ref.41 ref.42 ref.43 ref.44 ref.45 ref.46 ref.47 ref.48 ref.49 ref.50 ref.51 ref.52 ref.53 ref.54 ref.55 ref.56 ref.57 ref.77 ref.78 ref.79 ref.80 ref.81 ref.82 ref.83 ref.84 ref.85 ref.86 ref.87 ref.88 ref.89 ref.90 ref.91 ref.92 ref.93 ref.94 ref.95 ref.96 ref.97 ref.98 ref.99 ref.100 ref.101 ref.102 ref.103 ref.104 ref.105 ref.106 ref.107 ref.108 ref.109 ref.110 ref.111 ref.112 ref.113 ref.114 ref.115 ref.116 ref.117 ref.118 ref.119 ref.120 ref.121 ref.122 ref.123 ref.124 ref.125 ref.126 ref.127 ref.128 ref.129 ref.130 ref.131 ref.132 ref.133 ref.134 ref.135 ref.136 ref.137 ref.138 ref.139 ref.140 ref.141 ref.142 ref.143 ref.144 ref.145 ref.146 ref.147 ref.148 ref.149 ref.150 ref.151 ref.152 ref.153 ref.154 ref.155 ref.156 ref.157&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Clean up .sign files&lt;br /&gt;
rm -f *.sign&lt;br /&gt;
# Name the signature file for i.spec.sam&lt;br /&gt;
sigfname=&amp;quot;KL.sig&amp;quot;&lt;br /&gt;
rm -f $sigfname&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;# Signatures for Hyperion image of KL&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Water in river&lt;br /&gt;
classname=&amp;quot;water1&amp;quot;&lt;br /&gt;
coords=&amp;quot;215455.8579625377,383556.12608450593&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
# Define cols number in sig file&lt;br /&gt;
lno=$(cat temp | wc -l)&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
rm -f temp1&lt;br /&gt;
for number in $(cat temp)&lt;br /&gt;
do&lt;br /&gt;
    printf &amp;quot;%.8f &amp;quot; $number &amp;gt;&amp;gt; temp1&lt;br /&gt;
done&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp1 &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Forest area&lt;br /&gt;
classname=&amp;quot;forest1&amp;quot;&lt;br /&gt;
coords=&amp;quot;199906.1669829222,331418.4535104364&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
rm -f temp1&lt;br /&gt;
for number in $(cat temp)&lt;br /&gt;
do&lt;br /&gt;
    printf &amp;quot;%.8f &amp;quot; $number &amp;gt;&amp;gt; temp1&lt;br /&gt;
done&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp1 &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define rows number in sig file&lt;br /&gt;
signo=$(ls *.sign | wc -l)&lt;br /&gt;
&lt;br /&gt;
# Complete the sig file&lt;br /&gt;
echo &amp;quot;# &amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
echo &amp;quot;Matrix: $signo by $lno&amp;quot; &amp;gt;&amp;gt; $sigfname &lt;br /&gt;
n=0&lt;br /&gt;
for file in *.sign&lt;br /&gt;
do&lt;br /&gt;
    echo &amp;quot;row$n: $(cat $file)&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
    n=$(echo &amp;quot;$n + 1&amp;quot; | bc)&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Define the imagery working group&lt;br /&gt;
listmaps=$(echo $listf | sed 's/\ /,/g')&lt;br /&gt;
i.group group=temp input=$listmaps --quiet&lt;br /&gt;
&lt;br /&gt;
# Run a first set of Spectral Angle convergence&lt;br /&gt;
i.spec.sam group=temp input=$sigfname result=s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27332</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27332"/>
		<updated>2023-12-02T11:07:57Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Signatures preparation and launching i.spec.sam */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]][[File:HyperionR50G35B100.png||100px]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Signatures preparation and launching i.spec.sam ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Define the Hyperion files available for processing&lt;br /&gt;
listf=&amp;quot;ref.8 ref.9 ref.10 ref.11 ref.12 ref.13 ref.14 ref.15 ref.16 ref.17 ref.18 ref.19 ref.20 ref.21 ref.22 ref.23 ref.24 ref.25 ref.26 ref.27 ref.28 ref.29 ref.30 ref.31 ref.32 ref.33 ref.34 ref.35 ref.36 ref.37 ref.38 ref.39 ref.40 ref.41 ref.42 ref.43 ref.44 ref.45 ref.46 ref.47 ref.48 ref.49 ref.50 ref.51 ref.52 ref.53 ref.54 ref.55 ref.56 ref.57 ref.77 ref.78 ref.79 ref.80 ref.81 ref.82 ref.83 ref.84 ref.85 ref.86 ref.87 ref.88 ref.89 ref.90 ref.91 ref.92 ref.93 ref.94 ref.95 ref.96 ref.97 ref.98 ref.99 ref.100 ref.101 ref.102 ref.103 ref.104 ref.105 ref.106 ref.107 ref.108 ref.109 ref.110 ref.111 ref.112 ref.113 ref.114 ref.115 ref.116 ref.117 ref.118 ref.119 ref.120 ref.121 ref.122 ref.123 ref.124 ref.125 ref.126 ref.127 ref.128 ref.129 ref.130 ref.131 ref.132 ref.133 ref.134 ref.135 ref.136 ref.137 ref.138 ref.139 ref.140 ref.141 ref.142 ref.143 ref.144 ref.145 ref.146 ref.147 ref.148 ref.149 ref.150 ref.151 ref.152 ref.153 ref.154 ref.155 ref.156 ref.157&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Clean up .sign files&lt;br /&gt;
rm -f *.sign&lt;br /&gt;
# Name the signature file for i.spec.sam&lt;br /&gt;
sigfname=&amp;quot;KL.sig&amp;quot;&lt;br /&gt;
rm -f $sigfname&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;# Signatures for Hyperion image of KL&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Water in river&lt;br /&gt;
classname=&amp;quot;water1&amp;quot;&lt;br /&gt;
coords=&amp;quot;215455.8579625377,383556.12608450593&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
# Define cols number in sig file&lt;br /&gt;
lno=$(cat temp | wc -l)&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Forest area&lt;br /&gt;
classname=&amp;quot;forest1&amp;quot;&lt;br /&gt;
coords=&amp;quot;199906.1669829222,331418.4535104364&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define rows number in sig file&lt;br /&gt;
signo=$(ls *.sign | wc -l)&lt;br /&gt;
&lt;br /&gt;
# Complete the sig file&lt;br /&gt;
echo &amp;quot;# &amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
echo &amp;quot;Matrix $signo by $lno&amp;quot; &amp;gt;&amp;gt; $sigfname &lt;br /&gt;
n=0&lt;br /&gt;
for file in *.sign&lt;br /&gt;
do&lt;br /&gt;
    echo &amp;quot;row$n: $(cat $file)&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
    n=$(echo &amp;quot;$n + 1&amp;quot; | bc)&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Define the imagery working group&lt;br /&gt;
listmaps=$(echo $listf | sed 's/\ /,/g')&lt;br /&gt;
i.group group=temp input=$listmaps&lt;br /&gt;
&lt;br /&gt;
# Run a first set of Spectral Angle convergence&lt;br /&gt;
i.spec.sam group=temp input=$sigfname result=s&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27331</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27331"/>
		<updated>2023-12-02T11:01:01Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Hyperion Hyperspectral Data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]][[File:HyperionR50G35B100.png||100px]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Signatures preparation and launching i.spec.sam ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Define the Hyperion files available for processing&lt;br /&gt;
listf=&amp;quot;ref.8 ref.9 ref.10 ref.11 ref.12 ref.13 ref.14 ref.15 ref.16 ref.17 ref.18 ref.19 ref.20 ref.21 ref.22 ref.23 ref.24 ref.25 ref.26 ref.27 ref.28 ref.29 ref.30 ref.31 ref.32 ref.33 ref.34 ref.35 ref.36 ref.37 ref.38 ref.39 ref.40 ref.41 ref.42 ref.43 ref.44 ref.45 ref.46 ref.47 ref.48 ref.49 ref.50 ref.51 ref.52 ref.53 ref.54 ref.55 ref.56 ref.57 ref.77 ref.78 ref.79 ref.80 ref.81 ref.82 ref.83 ref.84 ref.85 ref.86 ref.87 ref.88 ref.89 ref.90 ref.91 ref.92 ref.93 ref.94 ref.95 ref.96 ref.97 ref.98 ref.99 ref.100 ref.101 ref.102 ref.103 ref.104 ref.105 ref.106 ref.107 ref.108 ref.109 ref.110 ref.111 ref.112 ref.113 ref.114 ref.115 ref.116 ref.117 ref.118 ref.119 ref.120 ref.121 ref.122 ref.123 ref.124 ref.125 ref.126 ref.127 ref.128 ref.129 ref.130 ref.131 ref.132 ref.133 ref.134 ref.135 ref.136 ref.137 ref.138 ref.139 ref.140 ref.141 ref.142 ref.143 ref.144 ref.145 ref.146 ref.147 ref.148 ref.149 ref.150 ref.151 ref.152 ref.153 ref.154 ref.155 ref.156 ref.157&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Clean up .sign files&lt;br /&gt;
rm -f *.sign&lt;br /&gt;
# Name the signature file for i.spec.sam&lt;br /&gt;
sigfname=&amp;quot;KL.sig&amp;quot;&lt;br /&gt;
rm -f $sigfname&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;# Signatures for Hyperion image of KL&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Water in river&lt;br /&gt;
classname=&amp;quot;water1&amp;quot;&lt;br /&gt;
coords=&amp;quot;215455.8579625377,383556.12608450593&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
# Define cols number in sig file&lt;br /&gt;
lno=$(cat temp | wc -l)&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Forest area&lt;br /&gt;
classname=&amp;quot;forest1&amp;quot;&lt;br /&gt;
coords=&amp;quot;199906.1669829222,331418.4535104364&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define rows number in sig file&lt;br /&gt;
signo=$(ls *.sign | wc -l)&lt;br /&gt;
&lt;br /&gt;
# Complete the sig file&lt;br /&gt;
echo &amp;quot;# &amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
echo &amp;quot;Matrix $signo by $lno&amp;quot; &amp;gt;&amp;gt; $sigfname &lt;br /&gt;
n=0&lt;br /&gt;
for file in *.sign&lt;br /&gt;
do&lt;br /&gt;
    echo &amp;quot;row$n: $(cat $file)&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
    n=$(echo &amp;quot;$n + 1&amp;quot; | bc)&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Define the imagery working group&lt;br /&gt;
# If already existing and loaded, then empty it&lt;br /&gt;
i.group -l group=temp &amp;gt; temp&lt;br /&gt;
val=$(cat temp | wc -l)&lt;br /&gt;
if [ $val -ne &amp;quot;&amp;quot; ]&lt;br /&gt;
then i.group -r group=temp file=temp&lt;br /&gt;
fi&lt;br /&gt;
# Load it with the new set from $listf&lt;br /&gt;
i.group group=temp input=$(echo $listf | sed '/\ /,/') &lt;br /&gt;
&lt;br /&gt;
# Run a first set of Spectral Angle convergence&lt;br /&gt;
i.spec.sam group=temp input=$sigfname result=s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27330</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27330"/>
		<updated>2023-12-02T11:00:31Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]][[File:HyperionR50G35B100.png]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Signatures preparation and launching i.spec.sam ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Define the Hyperion files available for processing&lt;br /&gt;
listf=&amp;quot;ref.8 ref.9 ref.10 ref.11 ref.12 ref.13 ref.14 ref.15 ref.16 ref.17 ref.18 ref.19 ref.20 ref.21 ref.22 ref.23 ref.24 ref.25 ref.26 ref.27 ref.28 ref.29 ref.30 ref.31 ref.32 ref.33 ref.34 ref.35 ref.36 ref.37 ref.38 ref.39 ref.40 ref.41 ref.42 ref.43 ref.44 ref.45 ref.46 ref.47 ref.48 ref.49 ref.50 ref.51 ref.52 ref.53 ref.54 ref.55 ref.56 ref.57 ref.77 ref.78 ref.79 ref.80 ref.81 ref.82 ref.83 ref.84 ref.85 ref.86 ref.87 ref.88 ref.89 ref.90 ref.91 ref.92 ref.93 ref.94 ref.95 ref.96 ref.97 ref.98 ref.99 ref.100 ref.101 ref.102 ref.103 ref.104 ref.105 ref.106 ref.107 ref.108 ref.109 ref.110 ref.111 ref.112 ref.113 ref.114 ref.115 ref.116 ref.117 ref.118 ref.119 ref.120 ref.121 ref.122 ref.123 ref.124 ref.125 ref.126 ref.127 ref.128 ref.129 ref.130 ref.131 ref.132 ref.133 ref.134 ref.135 ref.136 ref.137 ref.138 ref.139 ref.140 ref.141 ref.142 ref.143 ref.144 ref.145 ref.146 ref.147 ref.148 ref.149 ref.150 ref.151 ref.152 ref.153 ref.154 ref.155 ref.156 ref.157&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Clean up .sign files&lt;br /&gt;
rm -f *.sign&lt;br /&gt;
# Name the signature file for i.spec.sam&lt;br /&gt;
sigfname=&amp;quot;KL.sig&amp;quot;&lt;br /&gt;
rm -f $sigfname&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;# Signatures for Hyperion image of KL&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Water in river&lt;br /&gt;
classname=&amp;quot;water1&amp;quot;&lt;br /&gt;
coords=&amp;quot;215455.8579625377,383556.12608450593&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
# Define cols number in sig file&lt;br /&gt;
lno=$(cat temp | wc -l)&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Forest area&lt;br /&gt;
classname=&amp;quot;forest1&amp;quot;&lt;br /&gt;
coords=&amp;quot;199906.1669829222,331418.4535104364&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define rows number in sig file&lt;br /&gt;
signo=$(ls *.sign | wc -l)&lt;br /&gt;
&lt;br /&gt;
# Complete the sig file&lt;br /&gt;
echo &amp;quot;# &amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
echo &amp;quot;Matrix $signo by $lno&amp;quot; &amp;gt;&amp;gt; $sigfname &lt;br /&gt;
n=0&lt;br /&gt;
for file in *.sign&lt;br /&gt;
do&lt;br /&gt;
    echo &amp;quot;row$n: $(cat $file)&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
    n=$(echo &amp;quot;$n + 1&amp;quot; | bc)&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Define the imagery working group&lt;br /&gt;
# If already existing and loaded, then empty it&lt;br /&gt;
i.group -l group=temp &amp;gt; temp&lt;br /&gt;
val=$(cat temp | wc -l)&lt;br /&gt;
if [ $val -ne &amp;quot;&amp;quot; ]&lt;br /&gt;
then i.group -r group=temp file=temp&lt;br /&gt;
fi&lt;br /&gt;
# Load it with the new set from $listf&lt;br /&gt;
i.group group=temp input=$(echo $listf | sed '/\ /,/') &lt;br /&gt;
&lt;br /&gt;
# Run a first set of Spectral Angle convergence&lt;br /&gt;
i.spec.sam group=temp input=$sigfname result=s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=File:HyperionR50G35B100.png&amp;diff=27329</id>
		<title>File:HyperionR50G35B100.png</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=File:HyperionR50G35B100.png&amp;diff=27329"/>
		<updated>2023-12-02T10:59:42Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27328</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27328"/>
		<updated>2023-12-02T10:56:52Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: Adding signatures to i.spec.sam&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Signatures preparation and launching i.spec.sam ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;shell&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# Define the Hyperion files available for processing&lt;br /&gt;
listf=&amp;quot;ref.8 ref.9 ref.10 ref.11 ref.12 ref.13 ref.14 ref.15 ref.16 ref.17 ref.18 ref.19 ref.20 ref.21 ref.22 ref.23 ref.24 ref.25 ref.26 ref.27 ref.28 ref.29 ref.30 ref.31 ref.32 ref.33 ref.34 ref.35 ref.36 ref.37 ref.38 ref.39 ref.40 ref.41 ref.42 ref.43 ref.44 ref.45 ref.46 ref.47 ref.48 ref.49 ref.50 ref.51 ref.52 ref.53 ref.54 ref.55 ref.56 ref.57 ref.77 ref.78 ref.79 ref.80 ref.81 ref.82 ref.83 ref.84 ref.85 ref.86 ref.87 ref.88 ref.89 ref.90 ref.91 ref.92 ref.93 ref.94 ref.95 ref.96 ref.97 ref.98 ref.99 ref.100 ref.101 ref.102 ref.103 ref.104 ref.105 ref.106 ref.107 ref.108 ref.109 ref.110 ref.111 ref.112 ref.113 ref.114 ref.115 ref.116 ref.117 ref.118 ref.119 ref.120 ref.121 ref.122 ref.123 ref.124 ref.125 ref.126 ref.127 ref.128 ref.129 ref.130 ref.131 ref.132 ref.133 ref.134 ref.135 ref.136 ref.137 ref.138 ref.139 ref.140 ref.141 ref.142 ref.143 ref.144 ref.145 ref.146 ref.147 ref.148 ref.149 ref.150 ref.151 ref.152 ref.153 ref.154 ref.155 ref.156 ref.157&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Clean up .sign files&lt;br /&gt;
rm -f *.sign&lt;br /&gt;
# Name the signature file for i.spec.sam&lt;br /&gt;
sigfname=&amp;quot;KL.sig&amp;quot;&lt;br /&gt;
rm -f $sigfname&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;# Signatures for Hyperion image of KL&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Water in river&lt;br /&gt;
classname=&amp;quot;water1&amp;quot;&lt;br /&gt;
coords=&amp;quot;215455.8579625377,383556.12608450593&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
# Define cols number in sig file&lt;br /&gt;
lno=$(cat temp | wc -l)&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Forest area&lt;br /&gt;
classname=&amp;quot;forest1&amp;quot;&lt;br /&gt;
coords=&amp;quot;199906.1669829222,331418.4535104364&amp;quot;&lt;br /&gt;
fname=&amp;quot;$classname.sign&amp;quot;&lt;br /&gt;
# Clean up temp file&lt;br /&gt;
rm -f temp&lt;br /&gt;
for file in $listf&lt;br /&gt;
do&lt;br /&gt;
    r.what map=$file coordinates=$coords separator='comma' &amp;gt;&amp;gt; temp&lt;br /&gt;
done&lt;br /&gt;
sed -i 's/\(.*\),,\(.*\)/\2/' temp&lt;br /&gt;
tr '\n' ' ' &amp;lt; temp &amp;gt; $fname&lt;br /&gt;
echo &amp;quot;# $classname&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
&lt;br /&gt;
# Define rows number in sig file&lt;br /&gt;
signo=$(ls *.sign | wc -l)&lt;br /&gt;
&lt;br /&gt;
# Complete the sig file&lt;br /&gt;
echo &amp;quot;# &amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
echo &amp;quot;Matrix $signo by $lno&amp;quot; &amp;gt;&amp;gt; $sigfname &lt;br /&gt;
n=0&lt;br /&gt;
for file in *.sign&lt;br /&gt;
do&lt;br /&gt;
    echo &amp;quot;row$n: $(cat $file)&amp;quot; &amp;gt;&amp;gt; $sigfname&lt;br /&gt;
    n=$(echo &amp;quot;$n + 1&amp;quot; | bc)&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Define the imagery working group&lt;br /&gt;
# If already existing and loaded, then empty it&lt;br /&gt;
i.group -l group=temp &amp;gt; temp&lt;br /&gt;
val=$(cat temp | wc -l)&lt;br /&gt;
if [ $val -ne &amp;quot;&amp;quot; ]&lt;br /&gt;
then i.group -r group=temp file=temp&lt;br /&gt;
fi&lt;br /&gt;
# Load it with the new set from $listf&lt;br /&gt;
i.group group=temp input=$(echo $listf | sed '/\ /,/') &lt;br /&gt;
&lt;br /&gt;
# Run a first set of Spectral Angle convergence&lt;br /&gt;
i.spec.sam group=temp input=$sigfname result=s&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27327</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27327"/>
		<updated>2023-12-02T08:51:49Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Import in GRASS, DN2Rad &amp;amp; Rad2Ref */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27326</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27326"/>
		<updated>2023-12-02T08:49:27Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Import in GRASS, DN2Rad &amp;amp; Rad2Ref */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - untar *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 1&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(8, 57+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_vnir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Apply Gain for VNIR&lt;br /&gt;
    for j in range(77, 224+1):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j)+&amp;quot;=dn.&amp;quot;+str(j)+&amp;quot;*10.0/&amp;quot;+str(gain_swir))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = float(rinfo_out[&amp;quot;min&amp;quot;])&lt;br /&gt;
        maximum = float(rinfo_out[&amp;quot;max&amp;quot;])&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27325</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27325"/>
		<updated>2023-12-02T08:26:11Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. &lt;br /&gt;
&lt;br /&gt;
Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. &lt;br /&gt;
&lt;br /&gt;
The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. &lt;br /&gt;
&lt;br /&gt;
On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). &lt;br /&gt;
&lt;br /&gt;
The i.eb.* modules and models deal with:&lt;br /&gt;
* conduction {{cmd|i.eb.soilheatflux}} (for thermal conduction in soils)&lt;br /&gt;
* convection i.eb.h_* especially (for thermal convection in atmosphere)&lt;br /&gt;
* residual method estimating the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). &lt;br /&gt;
&lt;br /&gt;
Additionally, a helper module {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness, necessary in latent heat flux estimation.&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000) Status: Incomplete Module&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002) Status: Incomplete Module&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27324</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27324"/>
		<updated>2023-12-02T08:25:00Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). &lt;br /&gt;
&lt;br /&gt;
The i.eb.* modules and models deal with:&lt;br /&gt;
* conduction {{cmd|i.eb.soilheatflux}} (for thermal conduction in soils)&lt;br /&gt;
* convection i.eb.h_* especially (for thermal convection in atmosphere)&lt;br /&gt;
* residual method estimating the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). &lt;br /&gt;
&lt;br /&gt;
Additionally, a helper module {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness, necessary in latent heat flux estimation.&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000) Status: Incomplete Module&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002) Status: Incomplete Module&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass-stable/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27323</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27323"/>
		<updated>2023-12-02T08:21:40Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Introduction */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). &lt;br /&gt;
&lt;br /&gt;
The i.eb.* modules and models deal with:&lt;br /&gt;
* conduction {{cmd|i.eb.soilheatflux}} (for thermal conduction in soils)&lt;br /&gt;
* convection i.eb.h_* especially (for thermal convection in atmosphere)&lt;br /&gt;
* residual method estimating the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). &lt;br /&gt;
&lt;br /&gt;
Additionally, a helper module {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness, necessary in latent heat flux estimation.&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000) Status: Incomplete Module&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002) Status: Incomplete Module&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27322</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27322"/>
		<updated>2023-12-02T08:17:32Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000) Status: Incomplete Module&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002) Status: Incomplete Module&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27321</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27321"/>
		<updated>2023-12-02T08:16:21Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* i.evapo.* modules/models are integrated models */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000) Status: Incomplete Module&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002) Status: Incomplete Module&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27320</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27320"/>
		<updated>2023-12-02T08:13:20Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
== i.evapo.* modules/models are integrated '''models'''==&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000)&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002)&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== Temporal Integration of Evapotranspiration ==&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27319</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27319"/>
		<updated>2023-12-02T08:11:41Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models'''.&lt;br /&gt;
&lt;br /&gt;
from the oldest that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen)&lt;br /&gt;
* Penman-Monteith {{cmd|i.evapo.pm}}&lt;br /&gt;
* Priestley-Taylor {{cmd|i.evapo.pt}} &lt;br /&gt;
* Hargreaves {{cmd|i.evapo.mh}}&lt;br /&gt;
&lt;br /&gt;
to newer that are in some form or another linked to thermal processes.&lt;br /&gt;
* Thermal index {{cmd|i.evapo.senay}}&lt;br /&gt;
* Biome thermal processes {{cmd|i.evapo.zk}} (global model based on typical info from biomes Albedo/soil heat flux)&lt;br /&gt;
* Thermodynamic processes {{cmd|i.evapo.potrad}} (potential ET if not water stress, based on astronomical equations only)&lt;br /&gt;
&lt;br /&gt;
Most developed thermodynamic models are:&lt;br /&gt;
* TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000)&lt;br /&gt;
* SEBS (i.evapo.sebs: Zhu et al, 2002)&lt;br /&gt;
* SEBAL {{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} (Bastiaanssen et al, 1998, 2001)&lt;br /&gt;
&lt;br /&gt;
and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}).&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27318</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27318"/>
		<updated>2023-12-02T08:05:14Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models''', from the oldest (Penman-Monteith {{cmd|i.evapo.pm}}, Priestley-Taylor {{cmd|i.evapo.pt}}, Hargreaves {{cmd|i.evapo.mh}}, etc) that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen) to newer that area in some form or another linked to thermal processes ({{cmd|i.evapo.senay}}: uses a thermal index), biome thermal processes ({{cmd|i.evapo.zk}}: global model based on typical info from biomes Albedo/soil heat flux) or more thermodynamic processes ({{cmd|i.evapo.potrad}}: potential ET if not water stress, based on astronomical equations only). Most developed thermodynamic models are TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000), SEBS (i.evapo.sebs: Zhu et al, 2002), SEBAL ({{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}}: Bastiaanssen et al, 1998, 2001), and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd|i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd|i.biomass}}.&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27317</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27317"/>
		<updated>2023-12-02T08:04:10Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||500px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models''', from the oldest (Penman-Monteith {{cmd|i.evapo.pm}}, Priestley-Taylor {{cmd|i.evapo.pt}}, Hargreaves {{cmd|i.evapo.mh}}, etc) that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen) to newer that area in some form or another linked to thermal processes ({{cmd|i.evapo.senay}}: uses a thermal index), biome thermal processes ({{cmd|i.evapo.zk}}: global model based on typical info from biomes Albedo/soil heat flux) or more thermodynamic processes ({{cmd|i.evapo.potrad}}: potential ET if not water stress, based on astronomical equations only). Most developed thermodynamic models are TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000), SEBS (i.evapo.sebs: Zhu et al, 2002), SEBAL ({{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}}: Bastiaanssen et al, 1998, 2001), and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd||i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd||i.biomass}}.&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||800px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27316</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27316"/>
		<updated>2023-12-02T08:03:43Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||800px||Alt=&amp;quot;Chemin, 2006, PhD Thesis&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models''', from the oldest (Penman-Monteith {{cmd|i.evapo.pm}}, Priestley-Taylor {{cmd|i.evapo.pt}}, Hargreaves {{cmd|i.evapo.mh}}, etc) that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen) to newer that area in some form or another linked to thermal processes ({{cmd|i.evapo.senay}}: uses a thermal index), biome thermal processes ({{cmd|i.evapo.zk}}: global model based on typical info from biomes Albedo/soil heat flux) or more thermodynamic processes ({{cmd|i.evapo.potrad}}: potential ET if not water stress, based on astronomical equations only). Most developed thermodynamic models are TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000), SEBS (i.evapo.sebs: Zhu et al, 2002), SEBAL ({{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}}: Bastiaanssen et al, 1998, 2001), and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
When integrated in time {{cmd||i.evapo.time}}, seasonal evapotranspiration can be computed and therefore permit a full monitoring of vegetation growth over the period. This is also a basis of crop yield estimation (see {{cmd||i.biomass}}.&lt;br /&gt;
&lt;br /&gt;
[[File:I_evapo_time.png||500px||Alt=&amp;quot;Temporal integration of ETa with data from a weather station&amp;quot;]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=File:I_evapo_time.png&amp;diff=27315</id>
		<title>File:I evapo time.png</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=File:I_evapo_time.png&amp;diff=27315"/>
		<updated>2023-12-02T07:57:27Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27314</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27314"/>
		<updated>2023-12-02T07:36:08Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png||800px]]&lt;br /&gt;
&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models''', from the oldest (Penman-Monteith {{cmd|i.evapo.pm}}, Priestley-Taylor {{cmd|i.evapo.pt}}, Hargreaves {{cmd|i.evapo.mh}}, etc) that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen) to newer that area in some form or another linked to thermal processes ({{cmd|i.evapo.senay}}: uses a thermal index), biome thermal processes ({{cmd|i.evapo.zk}}: global model based on typical info from biomes Albedo/soil heat flux) or more thermodynamic processes ({{cmd|i.evapo.potrad}}: potential ET if not water stress, based on astronomical equations only). Most developed thermodynamic models are TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000), SEBS (i.evapo.sebs: Zhu et al, 2002), SEBAL ({{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}}: Bastiaanssen et al, 1998, 2001), and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27313</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27313"/>
		<updated>2023-12-02T07:33:53Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:EnergyBalance.png]]&lt;br /&gt;
&lt;br /&gt;
The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models''', from the oldest (Penman-Monteith {{cmd|i.evapo.pm}}, Priestley-Taylor {{cmd|i.evapo.pt}}, Hargreaves {{cmd|i.evapo.mh}}, etc) that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen) to newer that area in some form or another linked to thermal processes ({{cmd|i.evapo.senay}}: uses a thermal index), biome thermal processes ({{cmd|i.evapo.zk}}: global model based on typical info from biomes Albedo/soil heat flux) or more thermodynamic processes ({{cmd|i.evapo.potrad}}: potential ET if not water stress, based on astronomical equations only). Most developed thermodynamic models are TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000), SEBS (i.evapo.sebs: Zhu et al, 2002), SEBAL ({{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}}: Bastiaanssen et al, 1998, 2001), and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=File:EnergyBalance.png&amp;diff=27312</id>
		<title>File:EnergyBalance.png</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=File:EnergyBalance.png&amp;diff=27312"/>
		<updated>2023-12-02T07:33:23Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27311</id>
		<title>Image processing/Evapotranspiration</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Image_processing/Evapotranspiration&amp;diff=27311"/>
		<updated>2023-12-02T07:20:45Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: Edit Evapotranspiration script for Landsat 8&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The '''radiation''' is coming from the planet's star, Earth has around 1800 W/m2 of incoming radiation from the sun (also called irradiance) at exo-atmospheric altitude.&lt;br /&gt;
&lt;br /&gt;
Atmospheric transfer of '''irradiance''' is subject to atmosphere particles interactions, scattering, diffraction, reflection, etc.&lt;br /&gt;
&lt;br /&gt;
When reaching the planetary surface, is it partially reflected in the shortwave by '''Albedo'''. Surface Albedo is the integrated 0.3-3 micro-meters reflectance, it reflects the shortwave energy coming from the sun by 5% on oceans, 15-25% on vegetation, 35-40% on sand/desert/beach, 60-80% on snow/clouds, roughly. This energy fraction is returned to atmosphere for complex interaction with gas particles again before leaving the atmosphere altogether.&lt;br /&gt;
&lt;br /&gt;
As for the shortwave surface balance, the '''energy''' is also received in the longwave, but interacts with the grey-body characteristics of the surface elements. The blackbody to greybody fraction is ruled by emissivity, a hidden component in the thermal spectrum (search for Temperature- Emissivity Separation algorithms). On Earth, emissivity is always above 0.9 (mostly 0.96-0.98). The Stefan-Boltzman equation is dealing with blackbody energy, and multiplying it by Emissivity transforms it to greybody energy emitted.&lt;br /&gt;
&lt;br /&gt;
Together, shortwave and longwave '''energy balance''' provide with the net radiation balance at the surface of the planetary body. This crucial term is the total energy available for thermodynamic fluxes to act on the surface of the planet. On a planet like Earth where there is a triple phase of a given molecule (H20, in gas, liquid, solid), energy available is used to transfer phases from lower energy to higher energy (sublimation, liquefaction, evaporation). Thermal transfers also happen as conduction (soil, rocks) and convection (atmosphere, oceans). The i.eb.* modules and models deal with conduction (i.eb.g0, for thermal conduction in soils), convection (i.eb.h_* especially, for thermal convection in atmosphere) and by residual method estimate the energy left for evaporation processes ({{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}} are examples). {{AddonCmd|i.eb.z0m}} is producing an estimation of the surface roughness.&lt;br /&gt;
&lt;br /&gt;
i.evapo.* modules/models are integrated '''models''', from the oldest (Penman-Monteith {{cmd|i.evapo.pm}}, Priestley-Taylor {{cmd|i.evapo.pt}}, Hargreaves {{cmd|i.evapo.mh}}, etc) that are not based on energy balance, but are computing some form of evapotranspiration (ETo: Evapotranspiration for a reference of 20cm well-watered grass, see FAO no56 report of Richard Allen) to newer that area in some form or another linked to thermal processes ({{cmd|i.evapo.senay}}: uses a thermal index), biome thermal processes ({{cmd|i.evapo.zk}}: global model based on typical info from biomes Albedo/soil heat flux) or more thermodynamic processes ({{cmd|i.evapo.potrad}}: potential ET if not water stress, based on astronomical equations only). Most developed thermodynamic models are TSEB (i.evapo.tseb: Two Source Energy Balance, Schmugge, Kustas, etc., 2000), SEBS (i.evapo.sebs: Zhu et al, 2002), SEBAL ({{cmd|i.eb.h_sebal01}}, {{cmd|i.eb.evapfr}}, {{cmd|i.eb.eta}}: Bastiaanssen et al, 1998, 2001), and some newer models like RESET and others. The list of models using thermodynamic principles is large now, and any willing to submit a code for any of them is most welcome.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* Manual pages:&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_energy_balance.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/topic_evapotranspiration.html&lt;br /&gt;
** http://grass.osgeo.org/grass70/manuals/keywords.html#evaporative%20fraction&lt;br /&gt;
* [https://svn.osgeo.org/grass/grass-promo/tutorials/grass_landsat_ETa/ Evapotranspiration mapping with Landsat 5TM in GRASS GIS]&lt;br /&gt;
&lt;br /&gt;
== Example script to process Landsat 8 Evapotranspiration ==&lt;br /&gt;
&amp;lt;source lang=shell&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
# This scripts imports, pre-processes and compute Evapotranspiration for Landsat 8&lt;br /&gt;
# Run in a Location compatible with your L8 dataset&lt;br /&gt;
&lt;br /&gt;
# Atmospheric Transmissivity single-way&lt;br /&gt;
tsw=0.75&lt;br /&gt;
# Light Use Efficiency (please change dependent on your crop/plant)&lt;br /&gt;
lue=1.0&lt;br /&gt;
&lt;br /&gt;
# Import files in GRASS&lt;br /&gt;
for file in *TIF&lt;br /&gt;
do&lt;br /&gt;
	r.in.gdal -e input=$file output=$(echo $file | sed 's/.TIF//') --o&lt;br /&gt;
done&lt;br /&gt;
# Set region to newly imported files&lt;br /&gt;
g.region -s raster=$(ls *TIF | grep B1.TIF | sed 's/.TIF//')&lt;br /&gt;
LC08=$(ls *TIF | grep B1.TIF | sed 's/1.TIF//')&lt;br /&gt;
&lt;br /&gt;
# Set metadata MTL file name&lt;br /&gt;
LC08met=$(ls *MTL.txt)&lt;br /&gt;
&lt;br /&gt;
# Import DEM&lt;br /&gt;
r.import input=dem.tif output=dem extent=region --o&lt;br /&gt;
# Extract date&lt;br /&gt;
date=$(i.landsat.toar input=$LC08 output=l8 metfile=$LC08met lsatmet=date --o) &lt;br /&gt;
echo $date&lt;br /&gt;
&lt;br /&gt;
# Apply Top of Atmosphere correction&lt;br /&gt;
i.landsat.toar input=$LC08 output=l8 metfile=$LC08met --o&lt;br /&gt;
&lt;br /&gt;
# Set NODATA&lt;br /&gt;
for file in $(g.list type=raster pattern=LC08*)&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$file setnull=0&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
#Set computing area to B10 active pixels&lt;br /&gt;
for n in 1 2 3 4 5 6 7 8 9&lt;br /&gt;
do&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),l8$n)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,l8$n --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
base=l8&lt;br /&gt;
# Create config files for 6s&lt;br /&gt;
year=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\1/')&lt;br /&gt;
mm=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\2/')&lt;br /&gt;
dd=$(cat *MTL* | grep DATE_ACQUIRED | grep -oP '(=)[^;]+' | sed 's/=\ \(.*\)/\1/' | sed 's/\(.*\)-\(.*\)-\(.*\)/\3/')&lt;br /&gt;
doy=$( date -I -d &amp;quot;$year-$mm-$dd&amp;quot; | date +%j)&lt;br /&gt;
hh=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\1/')&lt;br /&gt;
mn=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\2/')&lt;br /&gt;
ss=$(cat *MTL* | grep TIME | grep -oP '(=)[^;]+' | sed 's/=\ \&amp;quot;\(.*\):\(.*\):\(.*\)\.\(.*\)/\3/')&lt;br /&gt;
time=$(echo &amp;quot;$hh + ($mn / 60.0) + ($ss / 3600.0)&amp;quot; | bc -l)&lt;br /&gt;
lat=$(echo $(cat *MTL* | grep CORNER_ | grep LAT | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
lon=$(echo $(cat *MTL* | grep CORNER_ | grep LON | grep -oP '(=)[^;]+' | sed 's/=//' | awk '{s+=$1} END {print s}') &amp;quot;/4.0&amp;quot; |  bc -l)&lt;br /&gt;
echo &amp;quot;18                            - geometrical conditions=Landsat 8&amp;quot; &amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;$mm $dd $hh.$mm $lon $lat    - month day hh.ddd longitude latitude (&amp;quot;hh.ddd&amp;quot; is in GMT decimal hours)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - atmospheric model=midlatitude summer&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;1                            - aerosols model=continental&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;24                           - visibility [km] (aerosol model concentration)&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-0.110                       - mean target elevation above sea level [km]&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
echo &amp;quot;-1000                        - sensor on board a satellite&amp;quot; &amp;gt;&amp;gt; 6s_conf.txt&lt;br /&gt;
#For Band 1:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\1_conf.txt&lt;br /&gt;
echo &amp;quot;115                           - Coastal band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\1_conf.txt&lt;br /&gt;
#For Band 2:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\2_conf.txt&lt;br /&gt;
echo &amp;quot;116                           - Blue band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\2_conf.txt&lt;br /&gt;
#For Band 3:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\3_conf.txt&lt;br /&gt;
echo &amp;quot;117                           - Green band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\3_conf.txt&lt;br /&gt;
#For Band 4:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\4_conf.txt&lt;br /&gt;
echo &amp;quot;118                           - Red band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\4_conf.txt&lt;br /&gt;
#For Band 5:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\5_conf.txt&lt;br /&gt;
echo &amp;quot;120                           - NIR band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\5_conf.txt&lt;br /&gt;
#For Band 6:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\6_conf.txt&lt;br /&gt;
echo &amp;quot;122                           - SWIR1 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\6_conf.txt&lt;br /&gt;
#For Band 7:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\7_conf.txt&lt;br /&gt;
echo &amp;quot;123                           - SWIR2 band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\7_conf.txt&lt;br /&gt;
#For Band 8:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\8_conf.txt&lt;br /&gt;
echo &amp;quot;119                           - PAN band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\8_conf.txt&lt;br /&gt;
#For Band 9:&lt;br /&gt;
cat 6s_conf.txt &amp;gt; $base\9_conf.txt&lt;br /&gt;
echo &amp;quot;121                           - Cirrus band of OLI Landsat 8&amp;quot; &amp;gt;&amp;gt; $base\9_conf.txt&lt;br /&gt;
&lt;br /&gt;
# Compute Atmospheric correction&lt;br /&gt;
for file in $base\1 $base\2 $base\3 $base\4 $base\5 $base\6 $base\7 $base\8 $base\9&lt;br /&gt;
do&lt;br /&gt;
	i.atcorr -r $file elevation=dem parameters=$file\_conf.txt output=s$file --o&lt;br /&gt;
	r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),s$file)&amp;quot; --o&lt;br /&gt;
	g.rename raster=temp,s$file --o&lt;br /&gt;
	r.colors map=$file color=grey&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
# Create cloud Mask&lt;br /&gt;
g.rename raster=l83,l7.2&lt;br /&gt;
g.rename raster=l84,l7.3&lt;br /&gt;
g.rename raster=l85,l7.4&lt;br /&gt;
g.rename raster=l86,l7.5&lt;br /&gt;
g.rename raster=l810,l7.6&lt;br /&gt;
i.landsat.acca -5 -f input=l7. output=temp --o&lt;br /&gt;
g.rename raster=l7.2,l83&lt;br /&gt;
g.rename raster=l7.3,l84&lt;br /&gt;
g.rename raster=l7.4,l85&lt;br /&gt;
g.rename raster=l7.5,l86&lt;br /&gt;
g.rename raster=l7.6,l810&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp1=if(isnull(temp),0,1)&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskVIS=if(isnull(l810),null(),temp1)&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Apply mask&lt;br /&gt;
r.mask raster=maskVIS maskcats=0&lt;br /&gt;
&lt;br /&gt;
# Latitude map&lt;br /&gt;
r.latlong input=l81 output=latitude --o&lt;br /&gt;
&lt;br /&gt;
# Longitude map&lt;br /&gt;
r.latlong -l input=l81 output=longitude --o&lt;br /&gt;
&lt;br /&gt;
# i.albedo&lt;br /&gt;
i.albedo -8 -c input=sl81,sl82,sl83,sl84,sl85,sl86,sl87 output=l8alb --o&lt;br /&gt;
r.colors -e map=l8alb color=grey&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=ndvi&lt;br /&gt;
i.vi viname=ndvi red=sl84 nir=sl85 output=l8ndvi --o&lt;br /&gt;
r.colors map=l8ndvi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Update processing mask with water&lt;br /&gt;
r.mapcalc expression=&amp;quot;maskWATER=if(l8ndvi&amp;lt;=0,0,maskVIS)&amp;quot; --o&lt;br /&gt;
r.mask -r&lt;br /&gt;
r.mask raster=maskWATER maskcats=0&lt;br /&gt;
&lt;br /&gt;
# i.emissivity&lt;br /&gt;
i.emissivity input=l8ndvi output=l8emis --o&lt;br /&gt;
&lt;br /&gt;
# i.vi viname=savi&lt;br /&gt;
i.vi viname=savi red=sl84 nir=sl85 output=l8savi --o&lt;br /&gt;
r.colors map=l8savi color=ndvi&lt;br /&gt;
&lt;br /&gt;
# Daily Net Radiation (RNETD)&lt;br /&gt;
r.mapcalc expression=&amp;quot;temp=if(isnull(l810),null(),dem)&amp;quot; --o&lt;br /&gt;
r.slope.aspect elevation=temp slope=slopedd aspect=aspectdd --o&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=rnetd insol_time=sunhours day=$doy nprocs=8 --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8rnetd=rnetd/sunhours&amp;quot; --o&lt;br /&gt;
&lt;br /&gt;
# Instantaneous Net Radiation (RNET)&lt;br /&gt;
timelocal=$(echo &amp;quot;$time + (24.0 / 360.0) * $lon&amp;quot; | bc -l)&lt;br /&gt;
r.sun elevation=temp aspect=aspectdd slope=slopedd albedo=l8alb glob_rad=l8rnet day=$doy time=$timelocal nprocs=8 --o&lt;br /&gt;
&lt;br /&gt;
# Soil Heat Flux (G0)&lt;br /&gt;
r.mapcalc expression=&amp;quot;overpasstime=$time&amp;quot; --o&lt;br /&gt;
i.eb.soilheatflux albedo=l8alb ndvi=l8ndvi temperature=l810 netradiation=l8rnet localutctime=overpasstime output=l8g0 --o&lt;br /&gt;
&lt;br /&gt;
# Sensible Heat Flux (H)&lt;br /&gt;
i.eb.z0m -p input=l8savi output=z0m --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;T0dem=0.00612*dem+l810&amp;quot; --o&lt;br /&gt;
i.eb.hsebal01 -a netradiation=l8rnet soilheatflux=l8g0 aerodynresistance=z0m temperaturemeansealevel=T0dem frictionvelocitystar=0.32407 vapourpressureactual=1.511 output=l8h --o&lt;br /&gt;
&lt;br /&gt;
# Evaporative Fraction &amp;amp; Soil Moisture&lt;br /&gt;
i.eb.evapfr -m netradiation=l8rnet soilheatflux=l8g0 sensibleheatflux=l8h evaporativefraction=l8evapfr soilmoisture=l8sm --o&lt;br /&gt;
&lt;br /&gt;
# Actual Evapotranspiration (ETa)&lt;br /&gt;
i.eb.eta netradiationdiurnal=l8rnetd evaporativefraction=l8evapfr temperature=l810 output=l8eta --o&lt;br /&gt;
&lt;br /&gt;
# Biomass growth&lt;br /&gt;
r.mapcalc expression=&amp;quot;l8fpar=1.257*l8ndvi-0.161&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;doy=$doy&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;tsw=$tsw&amp;quot; --o&lt;br /&gt;
r.mapcalc expression=&amp;quot;lue=$lue&amp;quot; --o&lt;br /&gt;
i.biomass fpar=l8fpar lightuse_efficiency=lue latitude=latitude dayofyear=doy transmissivity_singleway=tsw water_availability=l8evapfr output=l8biom --o&lt;br /&gt;
&lt;br /&gt;
# Export everything we need&lt;br /&gt;
for rstF in l8eta l8sm l8biom l8ndvi l8alb l8rnet l8g0 l8rnetd&lt;br /&gt;
do&lt;br /&gt;
	r.null map=$rstF setnull=-100000-0&lt;br /&gt;
	r.out.gdal -c -m input=$rstF output=$rstF\_$year$mm$dd.tif nodata=-32768 --o&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Documentation]]&lt;br /&gt;
[[Category: Evapotranspiration]]&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27310</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27310"/>
		<updated>2023-12-02T07:01:48Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Hyperion Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    &lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27309</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27309"/>
		<updated>2023-12-02T07:00:37Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Import in GRASS, DN2Rad &amp;amp; Rad2Ref */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    &lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27308</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27308"/>
		<updated>2023-12-02T06:57:51Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Import in GRASS, DN2Rad &amp;amp; Rad2Ref */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - unzip *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    exit()&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27307</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27307"/>
		<updated>2023-12-02T06:57:12Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
=== Data perculiarity ===&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. &lt;br /&gt;
&lt;br /&gt;
For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. &lt;br /&gt;
&lt;br /&gt;
This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - untar *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    exit()&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27306</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27306"/>
		<updated>2023-12-02T06:55:57Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Extracting and preparing data */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
It seems that bands 1-8 are filled with NODATA, the same for bands 58 to 76, and again for 225 to 242. For this reason, the pre-processing script below is avoiding the atmospheric correction of those bands. This seems to be explained by the presence of two sensors inside the instrument, one dedicated to VNIR hyperspectral sensing and the second one dedicated to SWIR hyperspectral sensing. This is further reinforced by observing the overlapping of band wavelengths across bands 56-57 and 77-78.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - untar *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    exit()&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27305</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27305"/>
		<updated>2023-12-02T06:50:18Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Extracting and preparing data ===&lt;br /&gt;
The data is downloaded as a zip file (i.e. ''EO1H1260582015073110T1_1GST.zip'') uncompressing as a directory (i.e. ''EO1H1260582015073110T1_1GST/''). Inside exists another directory (i.e. ''EO1H1260582015073110T1/'').&lt;br /&gt;
&lt;br /&gt;
The files inside are following this type of listing:&lt;br /&gt;
* EO1H1260582015073110T1_B001_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B002_L1GST.TIF&lt;br /&gt;
* ...&lt;br /&gt;
* EO1H1260582015073110T1_B241_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_B242_L1GST.TIF&lt;br /&gt;
* EO1H1260582015073110T1_MTL_L1GST.TXT&lt;br /&gt;
* EO1H1260582015073110T1_PF2_01.fgdc&lt;br /&gt;
* README.txt&lt;br /&gt;
&lt;br /&gt;
Of which ''EO1H1260582015073110T1_MTL_L1GST.TXT'' is a Landsat type metadata header file (''MTL type'') well known to Landsat users.&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - untar *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    exit()&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27304</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27304"/>
		<updated>2023-12-02T06:42:16Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: Add pyGRASS script&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Import in GRASS, DN2Rad &amp;amp; Rad2Ref ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all HYPERION radiance .zip into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance zip files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 1st December, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes HYPERION images&lt;br /&gt;
# 1 - untar *.zip files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import glob&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the HYPERION Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/HYPERION&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;HYPERION&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .zip HYPERION radiance tracks downloaded&lt;br /&gt;
HYPERIONDirs = [&amp;quot;EO1H1260582015073110T1_1GST&amp;quot;]  # , &amp;quot;&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of HYPERION&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
# Define a KVP retrieval function&lt;br /&gt;
def findkvp(text, key):&lt;br /&gt;
    for item in text.split(&amp;quot;\n&amp;quot;):&lt;br /&gt;
        if key in item:&lt;br /&gt;
            return (item.strip())&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for HYPERIONDir in HYPERIONDirs:&lt;br /&gt;
    # Unzip all of your HYPERION images in all your directories&lt;br /&gt;
    #print(&amp;quot;Unzip HYPERION files in &amp;quot;, HYPERIONDir)&lt;br /&gt;
    #p = os.system(&amp;quot;unzip &amp;quot;+HYPERIONDir+&amp;quot;.zip&amp;quot;)&lt;br /&gt;
    # Go into the new created directory&lt;br /&gt;
    path = rsdatapath+'/'+HYPERIONDir+'/'+HYPERIONDir.split('_')[0]&lt;br /&gt;
    os.chdir(path)&lt;br /&gt;
    # Select the first file in the directory&lt;br /&gt;
    first = os.listdir(path)[0]&lt;br /&gt;
    print(first)&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c &amp;quot;+first+&amp;quot; -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(5)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer (unit is Km)&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=0.1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map (unit is km)&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import HYPERION in GRASS&lt;br /&gt;
    count = 0&lt;br /&gt;
    # To remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    # Define TIF list&lt;br /&gt;
    ext=['TIF','tif']&lt;br /&gt;
    listoftiffiles = [f for f in os.listdir(path) if any(f.endswith(e) for e in ext)]&lt;br /&gt;
    # Process import&lt;br /&gt;
    for file in listoftiffiles:&lt;br /&gt;
        outfile='dn.'+str(count)&lt;br /&gt;
        ringdal(input=file, output=outfile, quiet=QUIET)&lt;br /&gt;
        rnull(map=outfile, setnull=0, quiet=QUIET)&lt;br /&gt;
        count = count + 1&lt;br /&gt;
    # Read HYPERION image CRS TODO check that &amp;quot;first&amp;quot; has full path attached&lt;br /&gt;
    src = gdal.Open(first)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Read MTL file to import scene characteristics&lt;br /&gt;
    MTLfile = glob.glob('*MTL*', recursive=False)&lt;br /&gt;
    print(&amp;quot;Metadatafile is &amp;quot;,MTLfile)&lt;br /&gt;
    with open(MTLfile[0], 'r') as file:&lt;br /&gt;
        data = file.read()&lt;br /&gt;
&lt;br /&gt;
    gain_vnir = findkvp(data,&amp;quot;SCALING_FACTOR_VNIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    gain_swir = findkvp(data,&amp;quot;SCALING_FACTOR_SWIR&amp;quot;).split(&amp;quot;=&amp;quot;)[1]&lt;br /&gt;
    print(&amp;quot;Gains VNIR %d &amp;amp; SWIR %d&amp;quot; % (int(gain_vnir), int(gain_swir)))&lt;br /&gt;
    # Extract time mean values&lt;br /&gt;
    starttimestamp = findkvp(data,&amp;quot;START_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    endtimestamp = findkvp(data,&amp;quot;END_TIME&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    starttime = starttimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    endtime = endtimestamp.split(&amp;quot; &amp;quot;)[-1]&lt;br /&gt;
    decstarttime = float(starttime.split(&amp;quot;:&amp;quot;)[0])+float(starttime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(starttime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    decendtime = float(endtime.split(&amp;quot;:&amp;quot;)[0])+float(endtime.split(&amp;quot;:&amp;quot;)[1])/60.0+float(endtime.split(&amp;quot;:&amp;quot;)[2])/3600.0&lt;br /&gt;
    dectime = 0.5 * (decstarttime + decendtime)&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(HYPERIONDir)&lt;br /&gt;
    acqdate = findkvp(data, &amp;quot;ACQUISITION_DATE&amp;quot;).split(&amp;quot;=&amp;quot;)[1].strip()&lt;br /&gt;
    date = [acqdate.split(&amp;quot;-&amp;quot;)[0], acqdate.split(&amp;quot;-&amp;quot;)[1], acqdate.split(&amp;quot;-&amp;quot;)[2]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # HYPERION DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for HYPERION&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # Create the handle for r.out.gdal&lt;br /&gt;
    routgdal = Module('r.out.gdal')&lt;br /&gt;
    exit()&lt;br /&gt;
    # Process VNIR&lt;br /&gt;
    # satellite band number (HYPERION VNIR [433-481])&lt;br /&gt;
    satbandno = 433  # Band 8 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(8,57+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 32&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    # Process SWIR&lt;br /&gt;
    # satellite band number (HYPERION SWIR [482-628])&lt;br /&gt;
    satbandno = 482  # Band 77 of HYPERION is first for atmospheric correction&lt;br /&gt;
    for idx in range(77,224+1):&lt;br /&gt;
        # Geometrical conditions (HYPERION VNIR = 32, SWIR = 33)&lt;br /&gt;
        geom = 33&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=HYPERION&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, a satellite)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # i th band of HYPERION (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_HYPERION.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal(input=b_out, output=HYPERIONDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27303</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27303"/>
		<updated>2023-12-02T06:39:16Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Hyperion Hyperspectral Satellite */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Data ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27302</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27302"/>
		<updated>2023-12-02T06:38:32Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Satellite ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either [https://earthexplorer.usgs.gov/ EarthExplorer] or [https://glovis.usgs.gov/ USGS Global Visualization Viewer (GloVis)].&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27301</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27301"/>
		<updated>2023-12-02T06:36:57Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Satellite ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1 GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either EarthExplorer or USGS Global Visualization Viewer (GloVis).&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level 1 GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27300</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27300"/>
		<updated>2023-12-02T06:36:35Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Satellite ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1GST is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either EarthExplorer or USGS Global Visualization Viewer (GloVis).&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Level GST specifications&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27299</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27299"/>
		<updated>2023-12-02T06:35:43Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Download */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Satellite ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;br /&gt;
Level 1Gst is terrain corrected and provided in 16-bit radiance values. The data are available in Geographic Tagged Image-File Format (GeoTIFF) and are distributed via download at no charge through either EarthExplorer or USGS Global Visualization Viewer (GloVis).&lt;br /&gt;
 	&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Caption text&lt;br /&gt;
|-&lt;br /&gt;
| Map projection || UTM (default zone of the scene center coordinates)&lt;br /&gt;
|-&lt;br /&gt;
| Horizontal Datum || WGS84&lt;br /&gt;
|-&lt;br /&gt;
| Resampling method || CC (cubic convolution)&lt;br /&gt;
|-&lt;br /&gt;
| Image orientation || Map (north up)&lt;br /&gt;
|-&lt;br /&gt;
| Pixel size || 30 meter (10 meter pan band)&lt;br /&gt;
|-&lt;br /&gt;
| Format || GeoTIFF&lt;br /&gt;
|-&lt;br /&gt;
| Output media || Download (no charge)&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27298</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27298"/>
		<updated>2023-12-02T06:29:55Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Hyperion Hyperspectral Satellite */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Satellite ==&lt;br /&gt;
[[File:eo1_satellite.jpg]]&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=File:Eo1_satellite.jpg&amp;diff=27297</id>
		<title>File:Eo1 satellite.jpg</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=File:Eo1_satellite.jpg&amp;diff=27297"/>
		<updated>2023-12-02T06:29:21Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27296</id>
		<title>Hyperion</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=Hyperion&amp;diff=27296"/>
		<updated>2023-12-02T06:26:42Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: Created page with &amp;quot;== Hyperion Hyperspectral Satellite ==  === EO-1 platform === The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]).   The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM).   The original EO-1 Mission was success...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Hyperion Hyperspectral Satellite ==&lt;br /&gt;
&lt;br /&gt;
=== EO-1 platform ===&lt;br /&gt;
The NASA EO-1 satellite was launched on November 21, 2000 as part of a one-year technology validation/demonstration mission ([https://www.usgs.gov/centers/eros/science/earth-observing-1-eo-1 EO-1 Mission Page]). &lt;br /&gt;
&lt;br /&gt;
The mission was to use the Advanced Land Imager (ALI) instrument on EO-1 to validate and demonstrate technology for the Landsat Data Continuity Mission (LDCM). &lt;br /&gt;
&lt;br /&gt;
The original EO-1 Mission was successfully completed in November 2001. As the end of the Mission approached, the remote sensing research and scientific communities expressed high interest in continued acquisition of image data from EO-1. Based on this user interest and willingness to assist in funding continued operations, an agreement was reached between NASA and the USGS to allow continuation of the EO-1 Program as an Extended Mission.&lt;br /&gt;
&lt;br /&gt;
On February 22nd, 2017, the Earth-Observing One (EO-1) satellite was decommissioned.&lt;br /&gt;
&lt;br /&gt;
=== Sensors ===&lt;br /&gt;
* Advanced Land Imager (ALI)&lt;br /&gt;
* Hyperion&lt;br /&gt;
* Linear Etalon Imaging Spectrometer Array (LEISA) Atmospheric Corrector (LAC)&lt;br /&gt;
&lt;br /&gt;
The EO-1 Extended Mission was chartered to collect and distribute ALI multispectral and Hyperion hyperspectral products in response to Data Acquisition Requests (DARs). Under the Extended Mission provisions, image data acquired by EO-1 were archived and distributed by the USGS Center for Earth Resources Observation and Science (EROS) and placed in the public domain.&lt;br /&gt;
&lt;br /&gt;
== Data Download ==&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27295</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27295"/>
		<updated>2023-12-02T06:13:14Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* AVIRIS Hyperspectral Sensor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
[[File:aviris_text2.png]]&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
==== DN to Radiance Conversion ====&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Import in GRASS, gain correction (DN2Rad) &amp;amp; atmospheric correction (Rad2Ref) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27294</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27294"/>
		<updated>2023-12-02T06:12:46Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* AVIRIS Hyperspectral Sensor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
[[aviris_text2.png]]&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
==== DN to Radiance Conversion ====&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Import in GRASS, gain correction (DN2Rad) &amp;amp; atmospheric correction (Rad2Ref) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27293</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27293"/>
		<updated>2023-12-02T06:11:42Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* AVIRIS Hyperspectral Sensor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
[[AVIRIS_text2.png]]&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
==== DN to Radiance Conversion ====&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Import in GRASS, gain correction (DN2Rad) &amp;amp; atmospheric correction (Rad2Ref) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=File:Aviris_text2.png&amp;diff=27292</id>
		<title>File:Aviris text2.png</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=File:Aviris_text2.png&amp;diff=27292"/>
		<updated>2023-12-02T06:10:40Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: Logo AVIRIS&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Logo AVIRIS&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27291</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27291"/>
		<updated>2023-12-02T06:08:18Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
==== DN to Radiance Conversion ====&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Import in GRASS, gain correction (DN2Rad) &amp;amp; atmospheric correction (Rad2Ref) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27290</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27290"/>
		<updated>2023-12-02T06:06:31Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
==== DN to Radiance Conversion ====&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Import in GRASS, gain correction (DN2Rad) &amp;amp; atmospheric correction (Rad2Ref) ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27289</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27289"/>
		<updated>2023-12-02T06:04:35Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Files of interest */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
==== DN to Radiance Conversion ====&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Importing script ===&lt;br /&gt;
&lt;br /&gt;
=== PyGRASS script to import and atmospherically correct AVIRIS ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27288</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27288"/>
		<updated>2023-12-02T06:02:44Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Data Downloaded */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
==== List of files ====&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
==== Files of interest ====&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
The DN to Radiance correction is done by applying a gain to the stored data in the BSQ file. In this case, the gain file in ''f180116t01p00r07rdn_e.gain''. Extracting the gain values can be done like this in Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
gain = []&lt;br /&gt;
with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
After that, the DN to Radiance correction can be done like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
&lt;br /&gt;
rmapcalc = Module('r.mapcalc')&lt;br /&gt;
# AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Importing script ===&lt;br /&gt;
&lt;br /&gt;
=== PyGRASS script to import and atmospherically correct AVIRIS ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
	<entry>
		<id>https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27287</id>
		<title>AVIRIS</title>
		<link rel="alternate" type="text/html" href="https://grasswiki.osgeo.org/w/index.php?title=AVIRIS&amp;diff=27287"/>
		<updated>2023-12-02T05:54:42Z</updated>

		<summary type="html">&lt;p&gt;⚠️Ychemin: /* Interface to copying maps (g.copy) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== AVIRIS Hyperspectral Sensor ==&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
'''AVIRIS''' is an acronym for the Airborne Visible InfraRed Imaging Spectrometer ([https://aviris.jpl.nasa.gov/ AVIRIS Main page]). &lt;br /&gt;
&lt;br /&gt;
Its optical sensor creates calibrated images of the upwelling spectral radiance in 224 contiguous spectral channels/bands with wavelengths from 400 to 2500 nanometers (nm). &lt;br /&gt;
&lt;br /&gt;
=== Airplanes ===&lt;br /&gt;
'''AVIRIS''' has been flown on four aircraft platforms: &lt;br /&gt;
* NASA's ER-2 jet&lt;br /&gt;
* Twin Otter International's turboprop &lt;br /&gt;
* Scaled Composites' Proteus &lt;br /&gt;
* NASA's WB-57. &lt;br /&gt;
&lt;br /&gt;
Flight details:&lt;br /&gt;
* The ER-2 flies at approximately 20km above sea level, at about 730 km/hr. &lt;br /&gt;
* The Twin Otter aircraft flies at 4km above ground level at 130km/hr. &lt;br /&gt;
&lt;br /&gt;
=== Data Download ===&lt;br /&gt;
Downloading data from '''AVIRIS''' flights is straightforward using the [https://aviris.jpl.nasa.gov/dataportal/ AVIRIS Data Portal].&lt;br /&gt;
&lt;br /&gt;
== Import AVIRIS in GRASS ==&lt;br /&gt;
=== Data Downloaded ===&lt;br /&gt;
&lt;br /&gt;
'''AVIRIS''' is downloaded as a .tar.gz file (i.e. ''f180116t01p00r07.tar.gz'') uncompressing as a directory (i.e. ''f180116t01p00r07rdn_e/'') containing with a set files like this:&lt;br /&gt;
&lt;br /&gt;
* AVIRIS_OrthoProcessing_Info.txt&lt;br /&gt;
* f180116t01p00r07rdn_e_eph&lt;br /&gt;
* f180116t01p00r07rdn_e.gain&lt;br /&gt;
* f180116t01p00r07rdn_e_lonlat_eph&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_obs_ort''&lt;br /&gt;
* f180116t01p00r07rdn_e_obs_ort.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_glt''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_glt.hdr&lt;br /&gt;
* ''f180116t01p00r07rdn_e_ort_igm''&lt;br /&gt;
* f180116t01p00r07rdn_e_ort_igm.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e_ort.plog&lt;br /&gt;
* f180116t01p00r07rdn_e.rccf18&lt;br /&gt;
* ''f180116t01p00r07rdn_e_sc01_ort_img''&lt;br /&gt;
* f180116t01p00r07rdn_e_sc01_ort_img.hdr&lt;br /&gt;
* f180116t01p00r07rdn_e.spc&lt;br /&gt;
&lt;br /&gt;
All files twinned with a .hdr file, and in italics in the list above, are ENVI style binary imagery datasets (''BSQ format''). Towards the end of the list, the file matching the pattern ''sc01'' is the largest file, and the one holding the actual hyperspectral data.&lt;br /&gt;
&lt;br /&gt;
=== Importing script ===&lt;br /&gt;
&lt;br /&gt;
=== PyGRASS script to import and atmospherically correct AVIRIS ===&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Process all AVIRIS radiance tar.gz into reflectance.&lt;br /&gt;
&lt;br /&gt;
Download all radiance tar.gz files into rsdatapath&lt;br /&gt;
Make sure GRASS GIS and python-gdal are installed&lt;br /&gt;
run this code after specifying your directories&lt;br /&gt;
&lt;br /&gt;
# Date: 24th October, 2023&lt;br /&gt;
# Public domain, GRASS GIS&lt;br /&gt;
&lt;br /&gt;
# PURPOSE&lt;br /&gt;
# This script processes AVIRIS images&lt;br /&gt;
# 1 - untar *.tar.gz files&lt;br /&gt;
# 2 - Connect files in GRASS GIS Location of your choice&lt;br /&gt;
# 3 - DN to Radiance (Apply Gain)&lt;br /&gt;
# 4 - Radiance to Surface reflectance (i.atcorr)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# Load necessary libraries&lt;br /&gt;
import os&lt;br /&gt;
import sys&lt;br /&gt;
import time&lt;br /&gt;
import struct&lt;br /&gt;
from subprocess import PIPE&lt;br /&gt;
# from osgeo import ogr&lt;br /&gt;
from osgeo import osr&lt;br /&gt;
from osgeo import gdal&lt;br /&gt;
# define GRASS-Python environment&lt;br /&gt;
os.environ['GISBASE'] = &amp;quot;/usr/local/grass84&amp;quot;&lt;br /&gt;
grass_pydir = os.path.join(&amp;quot;/usr/local/grass84&amp;quot;, &amp;quot;etc&amp;quot;, &amp;quot;python&amp;quot;)&lt;br /&gt;
sys.path.append(grass_pydir)&lt;br /&gt;
from grass.script import setup as gsetup&lt;br /&gt;
from grass.pygrass.modules.shortcuts import raster as r&lt;br /&gt;
from grass.pygrass.modules.shortcuts import imagery as i&lt;br /&gt;
from grass.pygrass.modules import Module&lt;br /&gt;
from grass.script.utils import parse_key_val&lt;br /&gt;
&lt;br /&gt;
# QUIET REPORTS&lt;br /&gt;
QUIET = True&lt;br /&gt;
&lt;br /&gt;
# OVERWRITE EXISTING FILES&lt;br /&gt;
OVR = True&lt;br /&gt;
&lt;br /&gt;
# Setup the path to the AVIRIS Directories&lt;br /&gt;
rsdatapath = &amp;quot;/home/yann/RSDATA/AVIRIS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Setup your GRASS GIS working directory&lt;br /&gt;
grassdata = &amp;quot;/home/yann/grassdata/&amp;quot;&lt;br /&gt;
location = &amp;quot;AVIRIS&amp;quot;&lt;br /&gt;
print(location)&lt;br /&gt;
mapset = &amp;quot;PERMANENT&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# DEM input for atmospheric correction&lt;br /&gt;
inDEM = &amp;quot;/home/yann/RSDATA/SRTM/dem.vrt&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Visibility distance [Km]&lt;br /&gt;
vis = 18&lt;br /&gt;
&lt;br /&gt;
# List of .tar.gz AVIRIS radiance tracks downloaded&lt;br /&gt;
AVIRISDirs = [&amp;quot;f180116t01p00r07&amp;quot;]  # , &amp;quot;f100517t01p00r11&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# CONFIGURATION OF 6S&lt;br /&gt;
# https://grass.osgeo.org/grass84/manuals/i.atcorr.html&lt;br /&gt;
&lt;br /&gt;
# Atmospheric mode&lt;br /&gt;
# none = 0&lt;br /&gt;
# tropical = 1&lt;br /&gt;
# midlatitude summer = 2&lt;br /&gt;
# midlatitude winter = 3&lt;br /&gt;
atm_mode = 1&lt;br /&gt;
# Aerosol model&lt;br /&gt;
# none = 0&lt;br /&gt;
# continental = 1&lt;br /&gt;
# maritime = 2&lt;br /&gt;
# urban = 3&lt;br /&gt;
aerosol_mode = 2&lt;br /&gt;
&lt;br /&gt;
# END OF USER CHANGES&lt;br /&gt;
# DO NOT CHANGE ANYTHING AFTER THIS LINE !&lt;br /&gt;
&lt;br /&gt;
# Change directory to find the tar.gz files of AVIRIS&lt;br /&gt;
os.chdir(rsdatapath)&lt;br /&gt;
&lt;br /&gt;
# Remove previous temporary GRASS Location&lt;br /&gt;
p = os.system(&amp;quot;rm -Rf &amp;quot;+grassdata+location)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def read_ephemeris_file(file_path):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    Read the ephemeris _eph file and extract flight altitude.&lt;br /&gt;
&lt;br /&gt;
    Parameters&lt;br /&gt;
    ----------&lt;br /&gt;
    file_path : STRING&lt;br /&gt;
        the ephemeris *_eph file.&lt;br /&gt;
&lt;br /&gt;
    Returns&lt;br /&gt;
    -------&lt;br /&gt;
    data : FLOAT&lt;br /&gt;
        the average height of sensor during flight.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    data = []&lt;br /&gt;
    # Define the format of a single record in the binary file&lt;br /&gt;
    record_format = 'd' * 6  # Six double-precision floating-point numbers&lt;br /&gt;
    with open(file_path, 'rb') as f:&lt;br /&gt;
        while True:&lt;br /&gt;
            record = f.read(struct.calcsize(record_format))&lt;br /&gt;
            if not record:&lt;br /&gt;
                break  # Reached end of file&lt;br /&gt;
            values = struct.unpack(record_format, record)&lt;br /&gt;
            data.append(values)&lt;br /&gt;
    return data&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# START PROCESS&lt;br /&gt;
# Read Gain from File&lt;br /&gt;
gain = []&lt;br /&gt;
# Start processing each radiance track bundlefrom DN to Ref&lt;br /&gt;
for AVIRISDir in AVIRISDirs:&lt;br /&gt;
    # Untar all of your AVIRIS images in all your directories&lt;br /&gt;
    print(&amp;quot;Untar AVIRIS files in &amp;quot;, AVIRISDir)&lt;br /&gt;
    #p = os.system(&amp;quot;tar xvf &amp;quot;+AVIRISDir+&amp;quot;.tar.gz&amp;quot;)&lt;br /&gt;
    with open(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e.gain&amp;quot;) as file:&lt;br /&gt;
        for line in file:&lt;br /&gt;
            gain.append(line.strip().split()[0])&lt;br /&gt;
    # Process a North alignment of the original file TODO add datatype=float&lt;br /&gt;
    kwargs = {'format': 'GTiff', 'geoloc': True, 'options': 'overwrite'}&lt;br /&gt;
    # gdal.UseExceptions()&lt;br /&gt;
    #ds = gdal.Warp(&amp;quot;del.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir + &amp;quot;rdn_e_sc01_ort_img&amp;quot;, **kwargs)&lt;br /&gt;
    #del ds&lt;br /&gt;
    # Create a temporary GRASS Location&lt;br /&gt;
    p = os.system(&amp;quot;grass -c del.tif -e &amp;quot;+grassdata+location)&lt;br /&gt;
    time.sleep(20)&lt;br /&gt;
    session = gsetup.init(grassdata, location, mapset)&lt;br /&gt;
    print(&amp;quot;Import in GRASS GIS&amp;quot;)&lt;br /&gt;
    # Import DEM for atmospheric correction&lt;br /&gt;
    ringdal = Module('r.in.gdal')&lt;br /&gt;
    # In case the DEM file is not empty&lt;br /&gt;
    # ringdal(input=AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_ort_igm&amp;quot;, output=&amp;quot;dem&amp;quot;,&lt;br /&gt;
    #         overwrite=OVR)&lt;br /&gt;
    # In case the DEM is available to import from srtm.csi.cgiar.org&lt;br /&gt;
    #rimport = Module('r.import')&lt;br /&gt;
    #rimport(input=inDEM, output=&amp;quot;dem&amp;quot;, extent=&amp;quot;region&amp;quot;, overwrite=OVR)&lt;br /&gt;
    # The least effective, make your own flat DEM layer&lt;br /&gt;
    rmapcalc = Module('r.mapcalc')&lt;br /&gt;
    rmapcalc(expression=&amp;quot;dem=1&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Create a visibility (AOD) map&lt;br /&gt;
    rmapcalc(expression=&amp;quot;vis=18&amp;quot;, overwrite=OVR)&lt;br /&gt;
    rmapcalc.wait()&lt;br /&gt;
    # Import AVIRIS in GRASS&lt;br /&gt;
    ringdal(input=&amp;quot;del.tif&amp;quot;, output=&amp;quot;dn&amp;quot;, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from DN maps&lt;br /&gt;
    rnull = Module('r.null')&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        rnull(map=&amp;quot;dn.&amp;quot;+str(idx+1), setnull=[-50, 0], quiet=QUIET)&lt;br /&gt;
    # Read rotated AVIRIS image&lt;br /&gt;
    src = gdal.Open(&amp;quot;del.tif&amp;quot;)&lt;br /&gt;
    ulx_, xres, xskew, uly_, yskew, yres = src.GetGeoTransform()&lt;br /&gt;
    lrx_ = ulx_ + (src.RasterXSize * xres)&lt;br /&gt;
    lry_ = uly_ + (src.RasterYSize * yres)&lt;br /&gt;
    # Setup the source projection&lt;br /&gt;
    source = osr.SpatialReference()&lt;br /&gt;
    source.ImportFromWkt(src.GetProjection())&lt;br /&gt;
    del src&lt;br /&gt;
    # The target projection is ll wgs84&lt;br /&gt;
    target = osr.SpatialReference()&lt;br /&gt;
    target.ImportFromEPSG(4326)&lt;br /&gt;
    # Create the transform&lt;br /&gt;
    transform = osr.CoordinateTransformation(source, target)&lt;br /&gt;
    # Transform the points&lt;br /&gt;
    uly, ulx, _ = transform.TransformPoint(ulx_, uly_)&lt;br /&gt;
    lry, lrx, _ = transform.TransformPoint(lrx_, lry_)&lt;br /&gt;
    # Import Auxiliary layers, rotate it first&lt;br /&gt;
    ds = gdal.Warp(&amp;quot;del1.tif&amp;quot;, AVIRISDir + &amp;quot;rdn_e/&amp;quot; + AVIRISDir +&lt;br /&gt;
                   &amp;quot;rdn_e_obs_ort&amp;quot;, **kwargs)&lt;br /&gt;
    del ds&lt;br /&gt;
    # Import in GRASS TODO force Float data&lt;br /&gt;
    ringdal(input=&amp;quot;del1.tif&amp;quot;, output=&amp;quot;obs&amp;quot;, flags=&amp;quot;e&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
    # Remove nodata from UTC map&lt;br /&gt;
    rnull(map=&amp;quot;obs.10&amp;quot;, setnull=[-9999, 0], quiet=QUIET)&lt;br /&gt;
    # Extract stats&lt;br /&gt;
    rinfo = Module('r.info', map=&amp;quot;obs.10&amp;quot;, flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
    rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
    # Extract mean values from Dict&lt;br /&gt;
    dectime = rinfo_out[&amp;quot;mean&amp;quot;]&lt;br /&gt;
    print(&amp;quot;timestamp &amp;quot;, str(dectime))&lt;br /&gt;
    print(AVIRISDir)&lt;br /&gt;
    date = [&amp;quot;20&amp;quot;+AVIRISDir[1:3], AVIRISDir[3:5], AVIRISDir[5:7]]&lt;br /&gt;
    print(date)&lt;br /&gt;
    # AVIRIS DN-&amp;gt;Rad-&amp;gt;Ref&lt;br /&gt;
    print(&amp;quot;Convert DN to Rad&amp;quot;)&lt;br /&gt;
    # Apply Gain from file&lt;br /&gt;
    for j in range(len(gain)):&lt;br /&gt;
        exp = str(&amp;quot;rad.&amp;quot;+str(j+1)+&amp;quot;=dn.&amp;quot;+str(j+1)+&amp;quot;*10.0/&amp;quot;+str(gain[j]))&lt;br /&gt;
        #print(exp)&lt;br /&gt;
        rmapcalc(expression=exp, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        rmapcalc.wait()&lt;br /&gt;
    # Atmospheric Correction&lt;br /&gt;
    print(&amp;quot;Atmospheric Correction&amp;quot;)&lt;br /&gt;
    # Basic script for i.atcorr for AVIRIS&lt;br /&gt;
    # Geometrical conditions (AVIRIS = 31)&lt;br /&gt;
    geom = 31&lt;br /&gt;
    # Sensor height (satellite is -1000)&lt;br /&gt;
    eph_data = read_ephemeris_file(AVIRISDir+&amp;quot;rdn_e/&amp;quot;+AVIRISDir+&amp;quot;rdn_e_eph&amp;quot;)&lt;br /&gt;
    # Extract average altitude&lt;br /&gt;
    add = 0&lt;br /&gt;
    for j in range(len(eph_data)):&lt;br /&gt;
        add += eph_data[j][2]&lt;br /&gt;
    height = add/len(eph_data)&lt;br /&gt;
    # Define the sensor height as Km and negative (for 6S)&lt;br /&gt;
    sens_height = -1*height/1000.0&lt;br /&gt;
    # Here we suppose you have altitude (DEM) and Visibility (VIS) maps ready&lt;br /&gt;
    # ---------------------------------------------&lt;br /&gt;
    # Altitude dummy value (in Km should be negative in this param file)&lt;br /&gt;
    # (overwritten by DEM raster input)&lt;br /&gt;
    alt = -0.600&lt;br /&gt;
    # datetime of satellite overpass (month, day, GMT decimal hour)&lt;br /&gt;
    mdh = str(date[1])+&amp;quot; &amp;quot;+str(date[2])+&amp;quot; &amp;quot;+str(&amp;quot;%.3f&amp;quot; % float(dectime))&lt;br /&gt;
    print(mdh)&lt;br /&gt;
    # Central Lat/Long&lt;br /&gt;
    Lon = ulx+(lrx-ulx)/2.0&lt;br /&gt;
    Lat = lry+(uly-lry)/2.0&lt;br /&gt;
    print(Lon, Lat)&lt;br /&gt;
    # satellite band number (AVIRIS [209-432])&lt;br /&gt;
    satbandno = 209  # Band 1 of AVIRIS is first for atmospheric correction&lt;br /&gt;
    for idx in range(224):&lt;br /&gt;
        b = &amp;quot;rad.&amp;quot; + str(idx+1)&lt;br /&gt;
        b_out = b.replace(&amp;quot;rad.&amp;quot;, &amp;quot;ref.&amp;quot;)&lt;br /&gt;
        # Extract min max radiance stats&lt;br /&gt;
        rinfo = Module('r.info', map=&amp;quot;rad.&amp;quot;+str(idx+1), flags=&amp;quot;s&amp;quot;, stdout_=PIPE)&lt;br /&gt;
        rinfo_out = parse_key_val(rinfo.outputs.stdout)&lt;br /&gt;
        # Extract mean values from Dict&lt;br /&gt;
        minimum = rinfo_out[&amp;quot;min&amp;quot;]&lt;br /&gt;
        maximum = rinfo_out[&amp;quot;max&amp;quot;]&lt;br /&gt;
        if (minimum &amp;lt; 0.0):&lt;br /&gt;
            minimum = 0.0&lt;br /&gt;
        param = []&lt;br /&gt;
        # geometrical conditions=AVIRIS&lt;br /&gt;
        param.append(str(geom)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # month day hh.ddd longitude latitude (hh.ddd is in decimal hours GMT)&lt;br /&gt;
        param.append(str(mdh)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lon)+&amp;quot; &amp;quot;+str(&amp;quot;%.2f&amp;quot; % Lat)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # atmospheric mode=tropical&lt;br /&gt;
        param.append(str(atm_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # aerosols model=maritime&lt;br /&gt;
        param.append(str(aerosol_mode)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # visibility [km] (aerosol model concentration), not used (raster input)\n&amp;quot;)&lt;br /&gt;
        param.append(str(vis)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # mean target elevation above sea level [km] (here 600m asl), not used (raster input)&lt;br /&gt;
        param.append(str(alt)+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # sensor height (here, sensor on board a plane)&lt;br /&gt;
        param.append(str(&amp;quot;%.2f&amp;quot; % round(sens_height,2))+&amp;quot;\n&amp;quot;)&lt;br /&gt;
        # puw (water vapor content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # po3 (ozone content between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # taerp (the aerosol optical thickness at 550nm between the aircraft and the surface)&lt;br /&gt;
        param.append(&amp;quot;-1.0\n&amp;quot;)&lt;br /&gt;
        # i th band of AVIRIS (atcorr internal no)&lt;br /&gt;
        param.append(str(satbandno))&lt;br /&gt;
        prm = &amp;quot;param_AVIRIS.txt&amp;quot;&lt;br /&gt;
        f = open(prm, &amp;quot;w&amp;quot;)&lt;br /&gt;
        f.writelines(param)&lt;br /&gt;
        f.close()&lt;br /&gt;
        print(b)&lt;br /&gt;
        print(b_out)&lt;br /&gt;
        iatcorr = Module('i.atcorr')&lt;br /&gt;
        iatcorr(input=b, elevation=&amp;quot;dem&amp;quot;, visibility=&amp;quot;vis&amp;quot;, parameters=prm,&lt;br /&gt;
                output=b_out, range=[minimum, maximum], rescale=[0.0,1.0], quiet=QUIET, overwrite=OVR)&lt;br /&gt;
        routgdal = Module('r.out.gdal')&lt;br /&gt;
        routgdal(input=b_out, output=AVIRISDir+&amp;quot;_&amp;quot;+b_out+&amp;quot;.tif&amp;quot;, overwrite=OVR, quiet=QUIET)&lt;br /&gt;
        satbandno = satbandno + 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>⚠️Ychemin</name></author>
	</entry>
</feed>