PROGRAM XML_2_GRD
! Utility program to read a CSEP-format seismicity forecast file
! (3.7 GB, with 31 magnitude bins from 5.95+-0.05 to 8.95+),
! and convert it to a single-magnitude-bin (all above threshold)
! forecast in Peter Bird's GRD format.
! This allows plotting with NeoKineMap, and also allows
! testing with Kagan_2009_GJI_I_scores and/or PseudoCSEP.
! Note that the spatial grid is unchanged; however,
! the forecast is also transformed from specific earthquake counts
! in a specific time window to earthquake rates densities
! (/m**2 /s) for an indefinite or open window.
! By Peter Bird, UCLA, 2014.05.12.
IMPLICIT NONE
CHARACTER*12 :: duration_days_c12
CHARACTER*79 :: GRD_file, line, XML_file
INTEGER, PARAMETER :: nMagnitudeBins = 31
INTEGER :: i, ios, iRow, j, jCol, k1, k2, n, nColumns, nRows, whole_steps
REAL, PARAMETER :: Earth_radius_m = 6371000.
REAL :: bottom_lat, &
& d_lat, d_lon, duration_days_real, duration_s, &
& EQ_count, EQ_rate_density, &
& highest_threshold, &
& lat, lat_max, lat_min, lon, lon_max, lon_min, lowest_threshold, &
& magnitudeBinDimension, magnitudeMinValue, &
& R2, &
& s_per_year, strip_area_steradian, &
& threshold_magnitude, top_lat
REAL, DIMENSION(nMagnitudeBins) :: magnitude_lower_limit
REAL, DIMENSION(:), ALLOCATABLE :: cell_area_m2 ! with one entry per row of seismicity matrix (N to S)
DOUBLE PRECISION, PARAMETER :: unity = 1.0D0
DOUBLE PRECISION, PARAMETER :: Pi = 3.141592654D0
DOUBLE PRECISION :: dx, dy, exponent, fk1, fk2, fraction, integral, integral_converted, radians_per_degree, total_area_m2
DOUBLE PRECISION, DIMENSION(nMagnitudeBins) :: earthquake_count ! for one cell, over duration_s, in magnitude bin #i = 1, ... , nMagnitudeBins
DOUBLE PRECISION, DIMENSION(nMagnitudeBins) :: log10_earthquake_rate_density ! in one cell, for indefinite duration, in magnitude bin #i = 1, ... , nMagnitudeBins
DOUBLE PRECISION, DIMENSION(:, :), ALLOCATABLE :: seismicity
radians_per_degree = Pi / 180.0D0
s_per_year = 365.25 * 24. * 60. * 60.
WRITE (*, "(' PROGRAM XML_2_GRD')")
WRITE (*, "(' ')")
WRITE (*, "(' Utility program to read a CSEP-format seismicity forecast file')")
WRITE (*, "(' (3.7 GB, with ',I2,' magnitude bins from 5.95+-0.05 to 8.95+),')") nMagnitudeBins
WRITE (*, "(' and convert it to a single-magnitude-bin (all above threshold)')")
WRITE (*, "(' forecast in Peter Bird''s GRD format.')")
WRITE (*, "(' This allows plotting with NeoKineMap, and also allows')")
WRITE (*, "(' testing with Kagan_2009_GJI_I_scores and/or PseudoCSEP.')")
WRITE (*, "(' Note that the spatial grid is unchanged; however,')")
WRITE (*, "(' the forecast is also transformed from specific earthquake counts')")
WRITE (*, "(' in a specific time window to earthquake rates densities')")
WRITE (*, "(' (/m**2 /s) for an indefinite or open window.')")
WRITE (*, "(' By Peter Bird, UCLA, 2014.05.12.')")
10 WRITE (*, *)
WRITE (*, "(' Enter name of existing XML file: '\)")
READ (*, "(A)") XML_file
WRITE (*, "(' Note that each OPEN takes a minute or two, for buffering...')")
OPEN (UNIT = 1, FILE = TRIM(XML_file), STATUS = "OLD", PAD = "YES", IOSTAT = ios)
IF (ios /= 0) THEN
WRITE (*, "(' ERROR: This file could not be found/opened (in current directory).')")
CALL Pause()
GO TO 10
END IF
WRITE (*, *)
WRITE (*, "(' HEADER LINES in this XML file:')")
WRITE (*, "(' -----------------------------------------------------------------------')")
DO i = 1, 16 ! expecting 16 lines of header information...
READ (1, "(A)") line
WRITE (*, "(' ',A)") TRIM(line)
IF (i == 11) THEN ! try to get duration_days_c12
IF (line(1:22) == " ") THEN
duration_days_c12 = line(23:34)
n = SCAN(duration_days_c12, '<') ! check for intrusion of
IF (n > 0) duration_days_c12(n:n) = ' ' ! create a space to permit READ(duration_days_c12, *)
READ (duration_days_c12, *, IOSTAT = ios) duration_days_real
IF (ios /= 0) THEN
WRITE (*, *)
WRITE (*, "(' ERROR: Could not get duration_days_real from: ',A)") duration_days_c12
CALL Pause()
STOP
END IF
duration_s = duration_days_real * 24. * 60. * 60.
ELSE
WRITE (*, *)
WRITE (*, "(' ERROR in file format: Expecting , but found:')")
WRITE (*, "(A)") TRIM(line)
CALL Pause()
STOP
END IF
END IF ! line #11: duration_day_c1
IF (i == 12) THEN ! try to get d_lat, d_lon
IF (line(1:28) == " ") THEN
line = line(28:79) ! cut out the prefix
n = SCAN(line, '<') !find start of
line(n:n) = ' ' !convert it to a space
READ (line, *, IOSTAT = ios) magnitudeBinDimension
IF (ios /= 0) THEN
WRITE (*, *)
WRITE (*, "(' ERROR: Could not get magnitudeBinDimension from start of string: '/' ', A)") TRIM(line)
CALL Pause()
STOP
END IF
ELSE
WRITE (*, *)
WRITE (*, "(' ERROR: Expecting but found: '/' ', A)") TRIM(line)
CALL Pause()
STOP
END IF
END IF ! line #13: magnitudeBinDimension
IF (i == 14) THEN ! line #14: magnitudeminValue
IF (line(1:23) == " ") THEN
line = line(24:79) ! cut out the prefix
n = SCAN(line, '<') !find start of
line(n:n) = ' ' !convert it to a space
READ (line, *, IOSTAT = ios) magnitudeMinValue
IF (ios /= 0) THEN
WRITE (*, *)
WRITE (*, "(' ERROR: Could not get magnitudeMinValue from start of string: '/' ', A)") TRIM(line)
CALL Pause()
STOP
END IF
ELSE
WRITE (*, *)
WRITE (*, "(' ERROR: Expecting but found: '/' ', A)") TRIM(line)
CALL Pause()
STOP
END IF
END IF ! line #14: magnitudeMinValue
END DO
WRITE (*, "(' -----------------------------------------------------------------------')")
WRITE (*, "(' Inferred forecast duration = ',ES12.5,' seconds.')") duration_s
WRITE (*, "(' Inferred d_lat = ',ES12.5,', d_lon = ',ES12.5)") d_lat, d_lon
WRITE (*, "(' Inferred magnitudeBinDimension = ',F6.3,', magnitudeMinValue = ',F6.3)") magnitudeBinDimension, magnitudeMinValue
magnitude_lower_limit(1) = magnitudeMinValue
DO i = 2, nMagnitudeBins
magnitude_lower_limit(i) = magnitude_lower_limit(i-1) + magnitudeBinDimension
END DO
CALL Pause()
!scan file for ranges of lon and lat:
WRITE (*, *)
WRITE (*, "(' Scanning XML file for extreme values of lon and lat (SLOW)...')")
lat_max = -9999.
lat_min = +9999.
lon_max = -9999.
lon_min = +9999.
scanning: DO
READ (1, "(A)", IOSTAT = ios) line
IF (ios /= 0) EXIT scanning
IF (line(1:16) == " highest_threshold)) THEN
WRITE (*, *)
WRITE (*, "(' ERROR: Please enter a threshold_magnitude value from ',F6.3,' to ',F6.3,';')") lowest_threshold, highest_threshold
WRITE (*, "(' because off-end extrapolation is limited to 2 bin-widths.')")
CALL Pause()
GO TO 90
END IF
whole_steps = (threshold_magnitude - magnitudeMinValue) / magnitudeBinDimension ! truncates to: whole-steps (ignoring suplus fraction) to right from lower-limit of lowest bin
k1 = whole_steps + 1 ! may be negative, at this point....
k1 = MAX(1, k1)
k1 = MIN((nMagnitudeBins-1), k1) ! within range from 1 ~ (nMagnitudeBins-1)
k2 = k1 + 1 ! within range from 2 ~ nMagnitudeBins
fraction = ((threshold_magnitude - magnitudeMinValue) / magnitudeBinDimension) - (k1 - 1.0) ! usually in 0.0 ~ 1.0, but not always!
fk1 = (1.0D0 - fraction) ! usually in 0.0 ~ 1.0, but not always!
fk2 = fraction ! usually in 0.0 ~ 1.0, but not always!
WRITE (*, *)
WRITE (*, "(' Log_10(seismicity) at threshold ',F6.3,' will get weight of ',F7.4)") magnitude_lower_limit(k1), fk1
WRITE (*, "(' Log_10(seismicity) at threshold ',F6.3,' will get weight of ',F7.4)") magnitude_lower_limit(k2), fk2
!select name for output GRD file:
WRITE (*, *)
WRITE (*, "(' Enter filename for new, output GRD file: '\)")
READ (*, "(A)") GRD_file
OPEN (UNIT = 2, FILE = TRIM(GRD_file)) ! unconditional OPEN; overwrites any existing file!
WRITE (*, *)
WRITE (*, "(' Starting primary working loop; SLOW ...')")
rescanning: DO
READ (1, "(A)", IOSTAT = ios) line
IF (ios /= 0) EXIT rescanning
IF (line(1:16) == " | |