@@ -48,7 +48,7 @@ def main(catalog_file, mc_file, pdf_file, m_file, m_select, mag_label, mc, m_max
import logging
from base_logger import getDefaultLogger
from timeit import default_timer as timer
from math import ceil , floor
from math import ceil , floor , isnan
import numpy as np
import scipy
import obspy
@@ -70,6 +70,8 @@ def main(catalog_file, mc_file, pdf_file, m_file, m_select, mag_label, mc, m_max
import matplotlib . pyplot as plt
from matplotlib . ticker import MultipleLocator
from matplotlib . contour import ContourSet
import xml . etree . ElementTree as ET
import json
logger = getDefaultLogger ( ' igfash ' )
@@ -239,6 +241,9 @@ verbose: {verbose}")
grid_y_max = int ( ceil ( y_max / grid_dim ) * grid_dim )
grid_y_min = int ( floor ( y_min / grid_dim ) * grid_dim )
grid_lat_max , grid_lon_max = utm . to_latlon ( grid_x_max , grid_y_max , utm_zone_number , utm_zone_letter )
grid_lat_min , grid_lon_min = utm . to_latlon ( grid_x_min , grid_y_min , utm_zone_number , utm_zone_letter )
# rectangular grid
nx = int ( ( grid_x_max - grid_x_min ) / grid_dim ) + 1
ny = int ( ( grid_y_max - grid_y_min ) / grid_dim ) + 1
@@ -434,22 +439,39 @@ verbose: {verbose}")
PGA = np . zeros ( shape = ( nx * ny ) )
# use dask parallel computing
start = timer ( )
pbar = ProgressBar ( )
pbar . register ( )
# iter = range(0,len(distances))
iter = indices
iml_grid_raw = [ ] # raw ground motion grids
for imt in products :
logger . info ( f " Estimating { imt } " )
imls = [ dask . delayed ( compute_IMT_exceedance ) ( rx_lat [ i ] , rx_lon [ i ] , distances [ i ] . flatten ( ) , fr , p , lambdas ,
forecast_len , lambdas_perc , m_range , m_pdf , m_cdf , model ,
log_level = logging . DEBUG , imt = imt , IMT_min = 0.0 , IMT_max = 2.0 ,
rx_label = i ) for i in iter ]
iml = dask . compu te( * imls )
iml_grid_raw . append ( list ( iml ) )
use_pp = False
if use_pp : # use dask parallel computing
pbar = ProgressBar ( )
pbar . regis ter ( )
# iter = range(0,len(distances) )
iter = indices
iml_grid_raw = [ ] # raw ground motion grids
for imt in products :
logger . info ( f " Estimating { imt } " )
imls = [ dask . delayed ( compute_IMT_exceedance ) ( rx_lat [ i ] , rx_lon [ i ] , distances [ i ] . flatten ( ) , fr , p , lambdas ,
forecast_len , lambdas_perc , m_range , m_pdf , m_cdf , model ,
log_level = logging . DEBUG , imt = imt , IMT_min = 0.0 , IMT_max = 2.0 , rx_label = i ,
rtol = 0.1 , use_cython = False ) for i in iter ]
iml = dask . compute ( * imls )
iml_grid_raw . append ( list ( iml ) )
else :
iml_grid_raw = [ ]
iter = indices
for imt in products :
iml = [ ]
for i in iter :
iml_i = compute_IMT_exceedance ( rx_lat [ i ] , rx_lon [ i ] , distances [ i ] . flatten ( ) , fr , p , lambdas , forecast_len ,
lambdas_perc , m_range , m_pdf , m_cdf , model , imt = imt , IMT_min = 0.0 ,
IMT_max = 2.0 , rx_label = i , rtol = 0.1 , use_cython = False )
iml . append ( iml_i )
logger . info ( f " Estimated { imt } at rx { i } is { iml_i } " )
iml_grid_raw . append ( iml )
end = timer ( )
logger . info ( f " Ground motion exceedance computation time: { round ( end - start , 1 ) } seconds " )
@@ -468,16 +490,6 @@ verbose: {verbose}")
else :
iml_grid_prep = iml_grid_raw
# TODO Remove. Saving coordinates to
# north, south = lat.max(), lat.min()
# east, west = lon.max(), lon.min()
# bbox_json = {"south": float(south), "west": float(west),
# "north": float(north), "east": float(east)}
# with open("overlay_bounds.json", "w", encoding="utf‑ 8") as fh:
# json.dump(bbox_json, fh, indent=2)
#
# logger.info(f"Saved bbox to overlay_bounds.json → {bbox_json}")
for j in range ( 0 , len ( products ) ) :
vmin = min ( x for x in iml_grid_prep [ j ] if x is not np . nan )
vmax = max ( x for x in iml_grid_prep [ j ] if x is not np . nan )
@@ -491,6 +503,12 @@ verbose: {verbose}")
mode = ' reflect ' , anti_aliasing = False )
iml_grid_hd [ iml_grid_hd == 0.0 ] = np . nan # change zeroes back to nan
# trim edges so the grid is not so blocky
vmin_hd = min ( x for x in iml_grid_hd . flatten ( ) if not isnan ( x ) )
vmax_hd = max ( x for x in iml_grid_hd . flatten ( ) if not isnan ( x ) )
trim_thresh = vmin
iml_grid_hd [ iml_grid_hd < trim_thresh ] = np . nan
# generate image overlay
north , south = lat . max ( ) , lat . min ( ) # Latitude range
east , west = lon . max ( ) , lon . min ( ) # Longitude range
@@ -499,55 +517,27 @@ verbose: {verbose}")
map_center = [ np . mean ( [ north , south ] ) , np . mean ( [ east , west ] ) ]
# Create an image from the grid
cmap_name = ' YlOrRd '
cmap = plt . get_cmap ( cmap_name )
fig , ax = plt . subplots ( figsize = ( 6 , 6 ) )
ax . imshow ( iml_grid_hd , origin = ' lower ' , cmap = ' viridis ' )
ax . imshow ( iml_grid_hd , origin = ' lower ' , cmap = cmap , vmin = vmin , vmax = vmax )
ax . axis ( ' off ' )
# Save the figure
fig . canvas . draw ( )
svg_path = f " overlay_ { j } .svg "
plt . savefig ( svg_path , bbox_inches = " tight " , pad_inches = 0 , transparent = True )
overlay_filename = f " overlay_ { j } .svg "
plt . savefig ( overlay_filename , bbox_inches = " tight " , pad_inches = 0 , transparent = True )
plt . close ( fig )
import xml . etree . ElementTree as ET # <-- TODO place this with other imports
import json
# -----------------------------------------
# Inject bounding box (BBOX) metadata into the SVG
# -----------------------------------------
north , south = lat . max ( ) , lat . min ( )
east , west = lon . max ( ) , lon . min ( )
bbox_dict = {
" south " : float ( south ) ,
" west " : float ( west ) ,
" north " : float ( north ) ,
" east " : float ( east )
}
tree = ET . parse ( svg_path )
root = tree . getroot ( )
# Remove any existing <metadata> tags
for old_meta in root . findall ( " { http://www.w3.org/2000/svg}metadata " ) :
root . remove ( old_meta )
# Add new <metadata> element with the bounding box JSON
meta_elem = ET . SubElement ( root , " metadata " )
meta_elem . text = json . dumps ( bbox_dict )
# (Optional) Also store the bounding box as a data attribute for quick access
root . set ( " data-bbox " , json . dumps ( bbox_dict ) )
tree . write ( svg_path , encoding = " utf-8 " , xml_declaration = True )
logger . info ( f " Embedded bbox into { svg_path } → { bbox_dict } " )
# -----------------------------------------
# END Inject bounding box (BBOX) metadata into the SVG
# -----------------------------------------
# Embed geographic bounding box into the SVG
map_bounds = dict ( zip ( ( " south " , " west " , " north " , " east " ) ,
map ( float , ( grid_lat_min , grid_lon_min , grid_lat_max , grid_lon_max ) ) ) )
tree = ET . parse ( overlay_filename )
tree . getroot ( ) . set ( " data-map-bounds " , json . dumps ( map_bounds ) )
tree . write ( overlay_filename , encoding = " utf-8 " , xml_declaration = True )
logger . info ( f " Saved geographic bounds to SVG metadata (data-map-bounds): { overlay_filename } → { map_bounds } " )
# Make the color bar
cmap_name = ' viridis '
width = 50
height = 500
@@ -555,16 +545,20 @@ verbose: {verbose}")
gradient = np . vstack ( ( gradient , gradient ) ) . T
gradient = np . tile ( gradient , ( 1 , width ) )
colorbar_title = products [ j ]
if " PGA " in colorbar_title or " SA " in colorbar_title :
colorbar_title = colorbar_title + " (g) "
fig , ax = plt . subplots ( figsize = ( ( width + 40 ) / 100.0 , ( height + 20 ) / 100.0 ) ,
dpi = 100 ) # Increase fig size for labels
ax . imshow ( gradient , aspect = ' auto ' , cmap = plt . get_cmap ( cmap_name ) ,
extent = [ 0 , 1 , vmin , vmax ] ) # Note: extent order is different for vertical
ax . imshow ( gradient , aspect = ' auto ' , cmap = cmap . reversed ( ) ,
extent = [ 0 , 1 , vmin , vmax_hd ] ) # Note: extent order is different for vertical
ax . set_xticks ( [ ] ) # Remove x-ticks for vertical colorbar
num_ticks = 11 # Show more ticks
tick_positions = np . linspace ( vmin , vmax , num_ticks )
tick_positions = np . linspace ( vmin , vmax_hd , num_ticks )
ax . set_yticks ( tick_positions )
ax . set_yticklabels ( [ f " { tick : .2f } " for tick in tick_positions ] ) # format tick labels
ax . set_title ( imt , pad = 15 )
ax . set_title ( colorbar_title , loc = ' right ' , pad = 15 )
fig . subplots_adjust ( left = 0.25 , right = 0.75 , bottom = 0.05 , top = 0.95 ) # Adjust Layout
fig . savefig ( " colorbar_ " + str ( j ) + " .svg " , bbox_inches = ' tight ' )
plt . close ( fig )