source_modelling.fsp

Module for handling FSP files.

This module provides classes and functions for reading FSP files, as well as representing their contents. See http://equake-rc.info/SRCMOD/fileformats/fsp/ for details on the FSP format.

Classes
  • FSPFile: Representation of an FSP file.
Exceptions
  • FSPParseError: Exception raised for errors in parsing FSP files.
Example
>>> fsp_file = FSPFile.read_from_file(fsp_ffp)
>>> (fsp_file.data['trup'] + fsp_file.data['rise']).max() # Get time of final rise for subfaults.
  1"""Module for handling FSP files.
  2
  3This module provides classes and functions for reading FSP files,
  4as well as representing their contents.
  5See http://equake-rc.info/SRCMOD/fileformats/fsp/
  6for details on the FSP format.
  7
  8Classes
  9-------
 10- FSPFile: Representation of an FSP file.
 11
 12Exceptions
 13----------
 14- FSPParseError: Exception raised for errors in parsing FSP files.
 15
 16Example
 17-------
 18>>> fsp_file = FSPFile.read_from_file(fsp_ffp)
 19>>> (fsp_file.data['trup'] + fsp_file.data['rise']).max() # Get time of final rise for subfaults.
 20"""
 21
 22import dataclasses
 23import re
 24from pathlib import Path
 25from typing import Callable, Optional
 26
 27import pandas as pd
 28import parse
 29
 30HEADER_PATTERN = """EventTAG: {event_tag}
 31Loc : LAT = {latitude:f} LON = {longitude:f} DEP = {depth:f}
 32Size : LEN = {length:f} km WID = {width:f} km Mw = {magnitude:f} Mo = {moment:e} Nm
 33Mech : STRK = {strike:f} DIP = {dip:f} RAKE = {rake:f} Htop = {htop:f} km
 34Rupt : HypX = {hypx:f} km Hypz = {hypz:f} km avTr = {average_rise_time:f} s avVr = {average_rupture_speed:f} km/s
 35Invs : Nx = {nx:d} Nz = {nz:d} Fmin = {fmin:f} Hz Fmax = {fmax:f} Hz
 36Invs : Dx = {dx:f} km Dz = {dz:f} km
 37Invs : Ntw = {time_window_count:d} Nsg = {segment_count:d} (# of time-windows,# of fault segments)
 38Invs : LEN = {time_window_length:f} s SHF = {time_shift:f} s (time-window length and time-shift)
 39SVF : {slip_velocity_function} (type of slip-velocity function used)
 40"""
 41
 42
 43def _normalise_value(value: float) -> Optional[float]:
 44    """Normalise an FSP parameter value.
 45
 46    Parameters
 47    ----------
 48    value : float
 49        The value to normalise.
 50
 51    Returns
 52    -------
 53    Optional[float]
 54        None if value is 999 or less than zero.
 55    """
 56    return None if value == 999 or value < 0 else value
 57
 58
 59class FSPParseError(Exception):
 60    """Exception raised for errors in parsing FSP files."""
 61
 62    pass
 63
 64
 65@dataclasses.dataclass
 66class FSPFile:
 67    """A representation of the FSP file format used to represent source models in SRCMOD.
 68
 69    Attributes
 70    ----------
 71    event_tag : str
 72        An identifier for the FSPFile, e.g. "s2004IRIANx01WEIx".
 73    latitude : float
 74        Latitude of hypocentre.
 75    longitude : float
 76        Longitude of hypocentre.
 77    depth : float
 78        Depth of hypocentre (in km).
 79    hypx : float or None
 80        The x-coordinate of the hypocentre (along strike, in km).
 81    hypz : float or None
 82        The z-coordinate of the hypocentre (along dip, in km).
 83    length : float
 84        The length of the rupture (in km).
 85    width : float
 86        The width of the rupture (in km).
 87    strike : float
 88        Rupture plane strike.
 89    dip : float
 90        Rupture plane dip.
 91    rake : float
 92        Rupture plane rake.
 93    htop : float
 94        Top depth of rupture plane (in km).
 95    magnitude : float
 96        Rupture magnitude.
 97    moment : float
 98        Rupture moment (in Nm).
 99    average_rise_time : float or None
100        Average rise time of subfaults.
101    average_rupture_speed : float or None
102        Average speed of rupture front.
103    slip_velocity_function : str
104        Description of the slip velocity function used
105    nx : float or None
106        The number of subfaults along strike.
107    nz : float or None
108        The number of subfaults along dip.
109    dx : float
110        The length of each subfault.
111    dz : float
112        The width of each subfault.
113    fmin : float or None
114        The minimum frequency in the inversion.
115    fmax : float or None
116        The maximum frequency in the inversion.
117    time_window_count : float or None
118        The slip (or rake) time windows for each subfault.
119    time_window_length : float or None
120        The time window length for each subfault.
121    time_shift : float or None
122        The time shift for each time window.
123    segment_count : int
124        Number of segments (subfaults).
125    data : pd.DataFrame
126        The data frame of info on each subfault.
127    """
128
129    event_tag: str
130
131    # Hypocentre parameters
132    latitude: float
133    longitude: float
134    depth: float
135    hypx: Optional[float]
136    hypz: Optional[float]
137
138    # Fault and parameters
139    length: float
140    width: float
141    strike: float
142    dip: float
143    rake: float
144    htop: float
145
146    # Rupture parameters
147    magnitude: float
148    moment: float
149    average_rise_time: Optional[float]
150    average_rupture_speed: Optional[float]
151    slip_velocity_function: str
152
153    # Model subfault sizes
154    nx: Optional[int]
155    nz: Optional[int]
156    dx: float
157    dz: float
158
159    # Inversion parameters
160    fmin: Optional[float]
161    fmax: Optional[float]
162
163    # Time window parameters
164    time_window_count: Optional[float]
165    time_window_length: Optional[float]
166    time_shift: Optional[float]
167
168    # Number of segments (== len(data))
169    segment_count: int
170    data: pd.DataFrame
171
172    @classmethod
173    def read_from_file(cls: Callable, fsp_ffp: Path) -> "FSPFile":
174        """Parse an FSPFile.
175
176        Parameters
177        ----------
178        fsp_ffp : Path
179            Path to the FSP file.
180
181        Returns
182        -------
183        FSPFile
184            The parsed FSPFile.
185        """
186        with open(fsp_ffp, "r") as fsp_file_handle:
187            header = ""
188            # Collect and normalise all the lines that make up the header
189            # of the file.
190            for line in fsp_file_handle:
191                if line.startswith("% Data :"):
192                    break
193                if (
194                    line.startswith("% -")
195                    or line.strip() == "%"
196                    or line.startswith("% Event :")
197                ):
198                    continue
199                # Strip the leading "% ", and deduplicate the spaces in the line.
200                # This is required to normalise the string so that the parse
201                # module can handle the rest of the parsing
202                header += " ".join(line.lstrip("% ").split()) + "\n"
203
204            # Now we can parse the header according to the header pattern.
205            parse_result = parse.parse(
206                HEADER_PATTERN,
207                header,
208            )
209            if not parse_result:
210                raise FSPParseError("Failed to parse FSP file header")
211            metadata = parse_result.named
212
213            # now sniff ahead for the columns
214            for line in fsp_file_handle:
215                if re.match(r"%\s+LAT\s+LON", line):
216                    break
217            else:
218                raise FSPParseError("Cannot find columns for FSP file!")
219            columns = line.lower().lstrip("% ").split()
220
221            data = pd.read_csv(
222                fsp_file_handle,
223                delimiter=r"\s+",
224                header=None,
225                names=columns,
226                comment="%",
227            )
228            data = data.rename(columns={"x==ew": "x", "y==ns": "y"})
229            fsp_file = cls(data=data, **metadata)
230
231            # A lot of parameters can be 999 or -999 to indicate "no known
232            # value", so we can detect that and set to None
233            fsp_file.hypx = _normalise_value(fsp_file.hypx)
234            fsp_file.hypz = _normalise_value(fsp_file.hypz)
235
236            fsp_file.average_rise_time = _normalise_value(fsp_file.average_rise_time)
237            fsp_file.average_rupture_speed = _normalise_value(
238                fsp_file.average_rupture_speed
239            )
240
241            fsp_file.nx = _normalise_value(fsp_file.nx)
242            fsp_file.nz = _normalise_value(fsp_file.nz)
243
244            fsp_file.fmin = _normalise_value(fsp_file.fmin)
245            fsp_file.fmax = _normalise_value(fsp_file.fmax)
246
247            fsp_file.time_window_count = _normalise_value(fsp_file.time_window_count)
248            fsp_file.time_window_length = _normalise_value(fsp_file.time_window_length)
249            fsp_file.time_shift = _normalise_value(fsp_file.time_shift)
250            return fsp_file
HEADER_PATTERN = 'EventTAG: {event_tag}\nLoc : LAT = {latitude:f} LON = {longitude:f} DEP = {depth:f}\nSize : LEN = {length:f} km WID = {width:f} km Mw = {magnitude:f} Mo = {moment:e} Nm\nMech : STRK = {strike:f} DIP = {dip:f} RAKE = {rake:f} Htop = {htop:f} km\nRupt : HypX = {hypx:f} km Hypz = {hypz:f} km avTr = {average_rise_time:f} s avVr = {average_rupture_speed:f} km/s\nInvs : Nx = {nx:d} Nz = {nz:d} Fmin = {fmin:f} Hz Fmax = {fmax:f} Hz\nInvs : Dx = {dx:f} km Dz = {dz:f} km\nInvs : Ntw = {time_window_count:d} Nsg = {segment_count:d} (# of time-windows,# of fault segments)\nInvs : LEN = {time_window_length:f} s SHF = {time_shift:f} s (time-window length and time-shift)\nSVF : {slip_velocity_function} (type of slip-velocity function used)\n'
class FSPParseError(builtins.Exception):
60class FSPParseError(Exception):
61    """Exception raised for errors in parsing FSP files."""
62
63    pass

Exception raised for errors in parsing FSP files.

@dataclasses.dataclass
class FSPFile:
 66@dataclasses.dataclass
 67class FSPFile:
 68    """A representation of the FSP file format used to represent source models in SRCMOD.
 69
 70    Attributes
 71    ----------
 72    event_tag : str
 73        An identifier for the FSPFile, e.g. "s2004IRIANx01WEIx".
 74    latitude : float
 75        Latitude of hypocentre.
 76    longitude : float
 77        Longitude of hypocentre.
 78    depth : float
 79        Depth of hypocentre (in km).
 80    hypx : float or None
 81        The x-coordinate of the hypocentre (along strike, in km).
 82    hypz : float or None
 83        The z-coordinate of the hypocentre (along dip, in km).
 84    length : float
 85        The length of the rupture (in km).
 86    width : float
 87        The width of the rupture (in km).
 88    strike : float
 89        Rupture plane strike.
 90    dip : float
 91        Rupture plane dip.
 92    rake : float
 93        Rupture plane rake.
 94    htop : float
 95        Top depth of rupture plane (in km).
 96    magnitude : float
 97        Rupture magnitude.
 98    moment : float
 99        Rupture moment (in Nm).
100    average_rise_time : float or None
101        Average rise time of subfaults.
102    average_rupture_speed : float or None
103        Average speed of rupture front.
104    slip_velocity_function : str
105        Description of the slip velocity function used
106    nx : float or None
107        The number of subfaults along strike.
108    nz : float or None
109        The number of subfaults along dip.
110    dx : float
111        The length of each subfault.
112    dz : float
113        The width of each subfault.
114    fmin : float or None
115        The minimum frequency in the inversion.
116    fmax : float or None
117        The maximum frequency in the inversion.
118    time_window_count : float or None
119        The slip (or rake) time windows for each subfault.
120    time_window_length : float or None
121        The time window length for each subfault.
122    time_shift : float or None
123        The time shift for each time window.
124    segment_count : int
125        Number of segments (subfaults).
126    data : pd.DataFrame
127        The data frame of info on each subfault.
128    """
129
130    event_tag: str
131
132    # Hypocentre parameters
133    latitude: float
134    longitude: float
135    depth: float
136    hypx: Optional[float]
137    hypz: Optional[float]
138
139    # Fault and parameters
140    length: float
141    width: float
142    strike: float
143    dip: float
144    rake: float
145    htop: float
146
147    # Rupture parameters
148    magnitude: float
149    moment: float
150    average_rise_time: Optional[float]
151    average_rupture_speed: Optional[float]
152    slip_velocity_function: str
153
154    # Model subfault sizes
155    nx: Optional[int]
156    nz: Optional[int]
157    dx: float
158    dz: float
159
160    # Inversion parameters
161    fmin: Optional[float]
162    fmax: Optional[float]
163
164    # Time window parameters
165    time_window_count: Optional[float]
166    time_window_length: Optional[float]
167    time_shift: Optional[float]
168
169    # Number of segments (== len(data))
170    segment_count: int
171    data: pd.DataFrame
172
173    @classmethod
174    def read_from_file(cls: Callable, fsp_ffp: Path) -> "FSPFile":
175        """Parse an FSPFile.
176
177        Parameters
178        ----------
179        fsp_ffp : Path
180            Path to the FSP file.
181
182        Returns
183        -------
184        FSPFile
185            The parsed FSPFile.
186        """
187        with open(fsp_ffp, "r") as fsp_file_handle:
188            header = ""
189            # Collect and normalise all the lines that make up the header
190            # of the file.
191            for line in fsp_file_handle:
192                if line.startswith("% Data :"):
193                    break
194                if (
195                    line.startswith("% -")
196                    or line.strip() == "%"
197                    or line.startswith("% Event :")
198                ):
199                    continue
200                # Strip the leading "% ", and deduplicate the spaces in the line.
201                # This is required to normalise the string so that the parse
202                # module can handle the rest of the parsing
203                header += " ".join(line.lstrip("% ").split()) + "\n"
204
205            # Now we can parse the header according to the header pattern.
206            parse_result = parse.parse(
207                HEADER_PATTERN,
208                header,
209            )
210            if not parse_result:
211                raise FSPParseError("Failed to parse FSP file header")
212            metadata = parse_result.named
213
214            # now sniff ahead for the columns
215            for line in fsp_file_handle:
216                if re.match(r"%\s+LAT\s+LON", line):
217                    break
218            else:
219                raise FSPParseError("Cannot find columns for FSP file!")
220            columns = line.lower().lstrip("% ").split()
221
222            data = pd.read_csv(
223                fsp_file_handle,
224                delimiter=r"\s+",
225                header=None,
226                names=columns,
227                comment="%",
228            )
229            data = data.rename(columns={"x==ew": "x", "y==ns": "y"})
230            fsp_file = cls(data=data, **metadata)
231
232            # A lot of parameters can be 999 or -999 to indicate "no known
233            # value", so we can detect that and set to None
234            fsp_file.hypx = _normalise_value(fsp_file.hypx)
235            fsp_file.hypz = _normalise_value(fsp_file.hypz)
236
237            fsp_file.average_rise_time = _normalise_value(fsp_file.average_rise_time)
238            fsp_file.average_rupture_speed = _normalise_value(
239                fsp_file.average_rupture_speed
240            )
241
242            fsp_file.nx = _normalise_value(fsp_file.nx)
243            fsp_file.nz = _normalise_value(fsp_file.nz)
244
245            fsp_file.fmin = _normalise_value(fsp_file.fmin)
246            fsp_file.fmax = _normalise_value(fsp_file.fmax)
247
248            fsp_file.time_window_count = _normalise_value(fsp_file.time_window_count)
249            fsp_file.time_window_length = _normalise_value(fsp_file.time_window_length)
250            fsp_file.time_shift = _normalise_value(fsp_file.time_shift)
251            return fsp_file

A representation of the FSP file format used to represent source models in SRCMOD.

Attributes
  • event_tag (str): An identifier for the FSPFile, e.g. "s2004IRIANx01WEIx".
  • latitude (float): Latitude of hypocentre.
  • longitude (float): Longitude of hypocentre.
  • depth (float): Depth of hypocentre (in km).
  • hypx (float or None): The x-coordinate of the hypocentre (along strike, in km).
  • hypz (float or None): The z-coordinate of the hypocentre (along dip, in km).
  • length (float): The length of the rupture (in km).
  • width (float): The width of the rupture (in km).
  • strike (float): Rupture plane strike.
  • dip (float): Rupture plane dip.
  • rake (float): Rupture plane rake.
  • htop (float): Top depth of rupture plane (in km).
  • magnitude (float): Rupture magnitude.
  • moment (float): Rupture moment (in Nm).
  • average_rise_time (float or None): Average rise time of subfaults.
  • average_rupture_speed (float or None): Average speed of rupture front.
  • slip_velocity_function (str): Description of the slip velocity function used
  • nx (float or None): The number of subfaults along strike.
  • nz (float or None): The number of subfaults along dip.
  • dx (float): The length of each subfault.
  • dz (float): The width of each subfault.
  • fmin (float or None): The minimum frequency in the inversion.
  • fmax (float or None): The maximum frequency in the inversion.
  • time_window_count (float or None): The slip (or rake) time windows for each subfault.
  • time_window_length (float or None): The time window length for each subfault.
  • time_shift (float or None): The time shift for each time window.
  • segment_count (int): Number of segments (subfaults).
  • data (pd.DataFrame): The data frame of info on each subfault.
FSPFile( event_tag: str, latitude: float, longitude: float, depth: float, hypx: Optional[float], hypz: Optional[float], length: float, width: float, strike: float, dip: float, rake: float, htop: float, magnitude: float, moment: float, average_rise_time: Optional[float], average_rupture_speed: Optional[float], slip_velocity_function: str, nx: Optional[int], nz: Optional[int], dx: float, dz: float, fmin: Optional[float], fmax: Optional[float], time_window_count: Optional[float], time_window_length: Optional[float], time_shift: Optional[float], segment_count: int, data: pandas.core.frame.DataFrame)
event_tag: str
latitude: float
longitude: float
depth: float
hypx: Optional[float]
hypz: Optional[float]
length: float
width: float
strike: float
dip: float
rake: float
htop: float
magnitude: float
moment: float
average_rise_time: Optional[float]
average_rupture_speed: Optional[float]
slip_velocity_function: str
nx: Optional[int]
nz: Optional[int]
dx: float
dz: float
fmin: Optional[float]
fmax: Optional[float]
time_window_count: Optional[float]
time_window_length: Optional[float]
time_shift: Optional[float]
segment_count: int
data: pandas.core.frame.DataFrame
@classmethod
def read_from_file(cls: Callable, fsp_ffp: pathlib.Path) -> FSPFile:
173    @classmethod
174    def read_from_file(cls: Callable, fsp_ffp: Path) -> "FSPFile":
175        """Parse an FSPFile.
176
177        Parameters
178        ----------
179        fsp_ffp : Path
180            Path to the FSP file.
181
182        Returns
183        -------
184        FSPFile
185            The parsed FSPFile.
186        """
187        with open(fsp_ffp, "r") as fsp_file_handle:
188            header = ""
189            # Collect and normalise all the lines that make up the header
190            # of the file.
191            for line in fsp_file_handle:
192                if line.startswith("% Data :"):
193                    break
194                if (
195                    line.startswith("% -")
196                    or line.strip() == "%"
197                    or line.startswith("% Event :")
198                ):
199                    continue
200                # Strip the leading "% ", and deduplicate the spaces in the line.
201                # This is required to normalise the string so that the parse
202                # module can handle the rest of the parsing
203                header += " ".join(line.lstrip("% ").split()) + "\n"
204
205            # Now we can parse the header according to the header pattern.
206            parse_result = parse.parse(
207                HEADER_PATTERN,
208                header,
209            )
210            if not parse_result:
211                raise FSPParseError("Failed to parse FSP file header")
212            metadata = parse_result.named
213
214            # now sniff ahead for the columns
215            for line in fsp_file_handle:
216                if re.match(r"%\s+LAT\s+LON", line):
217                    break
218            else:
219                raise FSPParseError("Cannot find columns for FSP file!")
220            columns = line.lower().lstrip("% ").split()
221
222            data = pd.read_csv(
223                fsp_file_handle,
224                delimiter=r"\s+",
225                header=None,
226                names=columns,
227                comment="%",
228            )
229            data = data.rename(columns={"x==ew": "x", "y==ns": "y"})
230            fsp_file = cls(data=data, **metadata)
231
232            # A lot of parameters can be 999 or -999 to indicate "no known
233            # value", so we can detect that and set to None
234            fsp_file.hypx = _normalise_value(fsp_file.hypx)
235            fsp_file.hypz = _normalise_value(fsp_file.hypz)
236
237            fsp_file.average_rise_time = _normalise_value(fsp_file.average_rise_time)
238            fsp_file.average_rupture_speed = _normalise_value(
239                fsp_file.average_rupture_speed
240            )
241
242            fsp_file.nx = _normalise_value(fsp_file.nx)
243            fsp_file.nz = _normalise_value(fsp_file.nz)
244
245            fsp_file.fmin = _normalise_value(fsp_file.fmin)
246            fsp_file.fmax = _normalise_value(fsp_file.fmax)
247
248            fsp_file.time_window_count = _normalise_value(fsp_file.time_window_count)
249            fsp_file.time_window_length = _normalise_value(fsp_file.time_window_length)
250            fsp_file.time_shift = _normalise_value(fsp_file.time_shift)
251            return fsp_file

Parse an FSPFile.

Parameters
  • fsp_ffp (Path): Path to the FSP file.
Returns
  • FSPFile: The parsed FSPFile.