"""This file contains the `rstt.SlbmInterface` class, which interfaces with the
raw `SlbmInterface` class exposed through `libslbmPyshell`."""

################################################################################
# 
#  Copyright 2009 National Technology & Engineering Solutions of Sandia, LLC
#  (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
#  Government retains certain rights in this software.
# 
#  BSD Open Source License
#  All rights reserved.
# 
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
# 
#    1. Redistributions of source code must retain the above copyright notice,
#       this list of conditions and the following disclaimer.
# 
#    2. Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
# 
#    3. Neither the name of the copyright holder nor the names of its
#       contributors may be used to endorse or promote products derived from
#       this software without specific prior written permission.
# 
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#  POSSIBILITY OF SUCH DAMAGE.
# 
################################################################################

#-----------------------------------------
# initialization
#-----------------------------------------

# everything that will be imported when we invoke `from .slbminterface import *`
__all__ = ["SlbmInterface"]

# import statements
from . import libslbmPyshell  # libslbmPyshell, imported from __init__.py
import os                     # check if files exist
from typing import Tuple      # type hinting (purely for code documentation)


#-----------------------------------------
# SlbmInterface class
#-----------------------------------------

class SlbmInterface(libslbmPyshell.SlbmInterface):
    """:class:`SlbmInterface` is the primary interface to the RSTT C++ library.

    :class:`SlbmInterface` is the primary interface to the RSTT C++ library,
    providing access to all supported functionality. It maintains a
    cpp:class:`Grid` object which is loaded into memory with the
    :meth:`~SlbmInterface.loadVelocityModel` method. This `Grid` object
    remains in memory until the :class:`SlbmInterface` destructor is called.

    :class:`SlbmInterface` also maintains a single instance of a `GreatCircle`
    object which is instantiated with a call to :meth:`~SlbmInterface.createGreatCircle`.
    Once instantiated, many methods can retrieve information from it, such as
    :meth:`~SlbmInterface.getTravelTime`, :meth:`~SlbmInterface.getTravelTimeComponents`,
    :meth:`~SlbmInterface.getWeights`, and more. The `GreatCircle` can be
    interrogated until it is replaced with another `GreatCircle` by a subsequent
    call to :meth:`~SlbmInterface.createGreatCircle`, or it is deleted by
    :meth:`~SlbmInterface.clear`.

    Examples
    --------
    >>> slbm = SlbmInterface()

    >>> slbm = SlbmInterface(6371.)

    Notes
    -----
        By default `earth_radius` is not set, and :class:`SlbmInterface` uses the
        values from the model file.

    Parameters
    ----------
    earth_radius : float, optional
        Constant radius of the Earth in kilometers

    Attributes
    ----------
    srcLat : float
        Source latitude (radians) passed to :meth:`~SlbmInterface.createGreatCircle`
        the last time it was called
    srcLon : float
        Source longitude (radians) passed to :meth:`~SlbmInterface.createGreatCircle`
        the last time it was called
    srcDep : float
        Source depth (km) passed to :meth:`~SlbmInterface.createGreatCircle`
        the last time it was called
    rcvLat : float
        Receiver latitude (radians) passed to :meth:`~SlbmInterface.createGreatCircle`
        the last time it was called
    rcvLon : float
        Receiver longitude (radians) passed to :meth:`~SlbmInterface.createGreatCircle`
        the last time it was called
    rcvDep : float
        Receiver depth (km) passed to :meth:`~SlbmInterface.createGreatCircle`
        the last time it was called
    valid : bool
        True if the current `GreatCircle` object has been instantiated and is
        ready to be interrogated.
    CH_MAX : float
        `c` is the Zhao `c` parameter, and `h` is the turning depth of the ray
        below the Moho. The Zhao method only valid for :math:`c*h << 1`.
        When :math:`c*h > CH_MAX`, then RSTT will throw an Exception.
    """

    def __init__(self, earth_radius: float = None) -> None:
        """Constructor for the :class:`SlbmInterface` class.

        Constructor for the :class:`SlbmInterface` class. You can provide an
        Earth radius (km), if you choose, but by default the tessellation of
        the Earth is read from the RSTT model.

        Examples
        --------
        >>> slbm = SlbmInterface()

        >>> slbm = SlbmInterface(6371.)

        Notes
        -----
            By default `earth_radius` is not set, and :class:`SlbmInterface`
            uses the values from the model file.

        Parameters
        ----------
        earth_radius : float, optional
            Constant radius of the Earth in kilometers

        Raises
        ------
        ValueError
            `earth_radius` is not an `int` or `float`, or more than 1 argument
            was given
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: earth_radius is an int or float
        if earth_radius is not None:
            if not isinstance(earth_radius, (int, float)):
                raise TypeError("earth_radius expects type 'int' or 'float', received '{}'".format(type(earth_radius).__name__))

        # try and construct the object
        try:
            if earth_radius:
                super().__init__(earth_radius)
            else:
                super().__init__()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def __eq__(self, other: object) -> bool:
        """Compares the model and/or great circle loaded into this and another
        SlbmInteface.

        This is an overloaded == operator which tests whether the model and/or
        great circle loaded by the current instantiation of SlbmInterface is
        equal to that of another SlbmInterface.

        Examples
        --------
        >>> slbm1 = SlbmInterface()
        >>> slbm2 = SlbmInterface()
        >>> slbm1.loadVelocityModel("example.geotess")
        >>> slbm2.loadVelocityModel("example.geotess")
        >>> slbm1 == slbm2
        True
        >>> slbm1.createGreatCircle("Pn", ...)
        >>> slbm2.createGreatCircle("Pg", ...)
        >>> slbm1 == slbm2
        False

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        """

        # if they're the same type, call the overloaded operator
        if type(self) == type(other):
            return super().__eq__(other)

        # if they're not the same type, they're definitely not equal
        else:
            return False


    def __ne__(self, other: object) -> bool:
        """This is simply the logical NOT complement to operator ==.

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        """

        # if they're the same type, call the overloaded operator
        if type(self) == type(other):
            return super().__ne__(other)

        # if they're not the same type, they're definitely not equal
        else:
            return True


    # PyBind11 does a good job dealing with the getters and setters for properties,
    # so there's no need to bother re-implementing them in here. It already works
    # well with rstt.SlbmInterface inheriting libslbmPyshell.SlbmInterface.

    # PyBind11 also deals with the SlbmInterface destructor.


    def getVersion(self) -> str:
        """Returns the RSTT version number.

        Examples
        --------
            >>> slbm.getVersion()

        Returns
        -------
        str
            The RSTT version number

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getVersion()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def clear(self) -> None:
        """Delete the current `GreatCircle` object from memory and clear the
        pool of stored `CrustalProfile` objects.

        The `Grid` object owned by :class:`SlbmInterface` stores a vector of map
        objects which associates the `phase` and `Location` of a
        `CrustalProfile` object with a pointer to the instance of the
        `CrustalProfile`. When :meth:`~SlbmInterface.createGreatCircle` is
        called with a `latitude`, `longitude`, and `depth` which has been used
        before, the `Grid` object will return a pointer to the existing
        `CrustalProfile` object, thereby enhancing performance. This vector of
        maps is cleared when :meth:`~SlbmInterface.clear` is called. The
        implications of all this is that applications that loop over many calls
        to :meth:`~SlbmInterface.createGreatCircle` will see a performance
        improvement if :meth:`~SlbmInterface.clear` is not called within the
        loop. However, for problems with a huge number of sources and or
        receivers, if memory becomes an issue, applications could call
        :meth:`~SlbmInterface.clear` within the loop to save memory.

        Examples
        --------
            >>> slbm.clear()

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().clear()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def clearActiveNodes(self) -> None:
        """Clear all active nodes.

        Examples
        --------
            >>> slbm.clearActiveNodes()

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().clearActiveNodes()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def clearNodeHitCount(self) -> None:
        """Clear the node hit count by setting the hit count of every node to zero.

        Examples
        --------
            >>> slbm.clearNodeHitCount()

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().clearNodeHitCount()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def createGreatCircle(self, phase: str or int,
            srcLatRad: float, srcLonRad: float, srcDepKm: float,
            rcvLatRad: float, rcvLonRad: float, rcvDepKm: float) -> None:
        """Instantiate a new `GreatCircle` between two locations.

        Instantiate a new `GreatCircle` objecr between a source and a receiver.
        Source and receiver locations are given in latitude/longitude with units
        of radians. Depths are given in kilometers. The `phase` can be given
        either as a string or an integer. Accepted values are:

            * `Pn` or `0`
            * `Sn` or `1`
            * `Pg` or `2`
            * `Lg` or `3`

        Examples
        --------
            >>> slbm.createGreatCircle("Lg", srcLatRad, srcLonRad, srcDepKm, rcvLatRad, rcvLonRad, rcvDepKm)
            >>> slbm.createGreatCircle(3, srcLatRad, srcLonRad, srcDepKm, rcvLatRad, rcvLonRad, rcvDepKm)

        Parameters
        ----------
        phase : str or int
            A phase name, or associated number. Accepted values are
                * `Pn` or `0`
                * `Sn` or `1`
                * `Pg` or `2`
                * `Lg` or `3`
        srcLatRad : float
            Source latitude, in radians
        srcLonRad : float
            Source longitude, in radians
        srcDepKm : float
            Source depth, in kilometers
        rcvLatRad : float
            Receiver latitude, in radians
        rcvLonRad : float
            Receiver longitude, in radians
        rcvDepKm : float
            Receiver depth, in kilometers

        Raises
        ------
        TypeError
            `phase` isn't an `int` or a `str`, or source/receiver locations
            aren't all `float`
        ValueError
            An inappropriate `phase` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: phase is an int or str
        if not isinstance(phase, (int, str)):  # phase is an int or string
            raise TypeError("`phase` expects type 'int' or 'str', received '{}'".format(type(phase).__name__))

        # ARG CHECK: str phase is one of [Pn, Sn, Pg, Lg]
        if isinstance(phase, str):
            if phase.lower() not in ('pn', 'sn', 'pg', 'lg'):
                raise ValueError("`phase` must be one of: 'Pn', 'Sn', 'Pg', or 'Lg'")

        # ARG CHECK: int phase is one of [0, 1, 2, 3]
        if isinstance(phase, int):
            if phase not in (0, 1, 2, 3):
                raise ValueError("`phase` must be one of: 0 (Pn), 1 (Sn), 2 (Pg), or 3 (Lg)")

        # ARG CHECK: source/receiver locations are all floats
        if not all(isinstance(arg, float) for arg in (srcLatRad, srcLonRad, srcDepKm, rcvLatRad, rcvLonRad, rcvDepKm)):
            raise TypeError("Source/receiver locations should all be type 'float'")

        # try and call the function
        try:
            super().createGreatCircle(phase, srcLatRad, srcLonRad, srcDepKm, rcvLatRad, rcvLonRad, rcvDepKm)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeData(self, nodeId: int) -> Tuple[float, float,
            Tuple[float,...], Tuple[float,...], Tuple[float,...], Tuple[float,...]]:
        """Retrieve information associated with a specified active node in the
        velocity grid.

        Retrieve the latitude, longitude, interface depths, P and S wave
        interval velocities and P and S mantle gradient information associated
        with a specified active node in the velocity grid.

        Examples
        --------
            >>> slbm.getActiveNodeData(1001)

        Parameters
        ----------
        nodeId : int
            Active node in the grid

        Returns
        -------
        latitude : float
            Latitude of the active node, in radians
        longitude : float
            Longitude of the active node, in radians
        depth : tuple of floats
            Depths of all the model interfaces, in kilometers
        pvelocity : tuple of floats
            P velocities of the intervals at the active node, in kilometers per second
        svelocity : tuple of floats
            S velocities of the intervals at the active node, in kilometers per second
        gradient : tuple of floats
            P and S velocity gradients in the mantle, in 1/second

        Raises
        ------
        TypeError
            `nodeId` isn't an `int`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # phase is an int or string
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # try and call the function
        try:
            return super().getActiveNodeData(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeId(self, nodeId: int) -> int:
        """Retrieve the active node ID that corresponds to a specified grid node ID.

        Examples
        --------
            >>> slbm.getActiveNodeId(1001)

        Parameters
        ----------
        nodeId : int
            Node in the grid

        Returns
        -------
        int
            Active node ID

        Raises
        ------
        TypeError
            `nodeId` isn't an `int`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # phase is an int or string
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # try and call the function
        try:
            return super().getActiveNodeId(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeNeighborInfo(self, nodeId: int) -> Tuple[Tuple[int,...], Tuple[float,...], Tuple[float,...]]:
        """Retrieve information about the nodes that surround the specified
        active node.

        Examples
        --------
            >>> slbm.getActiveNodeNeighborInfo(11)

        Parameters
        ----------
        nodeId : int
            Active node in the grid

        Returns
        -------
        tuple of ints
            Active node neighbors of the specified active node
        tuple of floats
            Distance of active node neighbors relative to specified active node
        tuple of floats
            Azimuth of active node neighbors relative to specified active node

        Raises
        ------
        TypeError
            `nodeId` isn't an `int`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # phase is an int or string
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # try and call the function
        try:
            return super().getActiveNodeNeighborInfo(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeNeighbors(self, nodeId: int) -> Tuple[int, ...]:
        """Retrieve the active node IDs of the active nodes that surround the
        specified active node.

        Examples
        --------
            >>> slbm.getActiveNodeNeighbors(11)

        Parameters
        ----------
        nodeId : int
            Active node in the grid

        Returns
        -------
        tuple of ints
            Active node IDs of the active nodes that surround the specified
            active node

        Raises
        ------
        TypeError
            `nodeId` isn't an `int`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # phase is an int or string
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # try and call the function
        try:
            return super().getActiveNodeNeighbors(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeWeights(self) -> Tuple[Tuple[int, ...], Tuple[float, ...]]:
        """Retrieve the weight assigned to each active node that was touched by
        the `GreatCircle`.

        Only nodes touched by this `GreatCircle` are included in the output.
        Each grid node is included only once, even though more than one
        `LayerProfile` object may have contributed some weight to it. The sum of
        all the weights will equal the horizontal distance traveled by the ray
        along the head wave interface, from the source pierce point to the
        receiver pierce point, in kilometers.

        Examples
        --------
            >>> slbm.getActiveNodeWeights()

        Returns
        -------
        tuple of ints
            Active node IDs touched by this `GreatCircle`
        tuple of floats
            Weights of the touched active nodes, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getActiveNodeWeights()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeWeightsReceiver(self) -> Tuple[Tuple[int, ...], Tuple[float, ...]]:
        """Retrieve the weight assigned to each active node for the receiver
        `CrustalProfile`.

         For linear interpolation, the returned number of weights will equal 3,
         but for natural neighbor interpolation it will be variable and less
         than 10.

        Examples
        --------
            >>> slbm.getActiveNodeWeightsReceiver()

        Returns
        -------
        tuple of ints
            Active node IDs for the receiver `CrustalProfile`
        tuple of floats
            Weights of the active nodes, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getActiveNodeWeightsReceiver()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getActiveNodeWeightsSource(self) -> Tuple[Tuple[int, ...], Tuple[float, ...]]:
        """Retrieve the weight assigned to each active node for the source
        `CrustalProfile`.

         For linear interpolation, the returned number of weights will equal 3,
         but for natural neighbor interpolation it will be variable and less
         than 10.

        Examples
        --------
            >>> slbm.getActiveNodeWeightsReceiver()

        Returns
        -------
        tuple of ints
            Active node IDs for the source `CrustalProfile`
        tuple of floats
            Weights of the active nodes, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getActiveNodeWeightsSource()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getAverageMantleVelocity(self, waveType: int or str) -> float:
        """Retrieve the average P or S wave mantle velocity that is specified in
        the model input file.

        Examples
        --------
            >>> slbm.getAverageMantleVelocity('P')

        Parameters
        ----------
        waveType : str or int
            Seismic wave type. Accepted values are
                * :attr:`~rstt.PWAVE`, `P`, or `0`
                * :attr:`~rstt.SWAVE`, `S`, or `1`

        Returns
        -------
        float
            Average mantle velocity, in kilometers per second

        Raises
        ------
        TypeError
            `waveType` isn't an `int` or a `str`
        ValueError
            An inappropriate `waveType` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: waveType is and int or str
        if not isinstance(waveType, (int, str)):  # waveType is an int or string
            raise TypeError("`waveType` expects type 'int' or 'str', received '{}'".format(type(waveType).__name__))

        # ARG CHECK: str waveType is one of [P, S]
        if isinstance(waveType, str):
            if waveType.lower() not in ('p', 's'):
                raise ValueError("`waveType` must be either 'P' or 'S'")

        # ARG CHECK: int waveType is one of [0, 1]
        if isinstance(waveType, int):
            if waveType not in (0, 1):
                raise ValueError("`waveType` must be 0 (P) or 1 (S)")

        # convert string waveType to int
        if isinstance(waveType, str):
            waveType = PWAVE if waveType.lower() == 'p' else SWAVE

        # try and call the function
        try:
            return super().getAverageMantleVelocity(waveType)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getBufferSize(self) -> int:
        """Returns the size of a `DataBuffer` object required to store this
        :class:`SlbmInterface` object's model data.

        Examples
        --------
            >>> slbm.getBufferSize()

        Returns
        -------
        int
            Size required to store this :class:`SlbmInterface` object's model
            data, in bytes

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getBufferSize()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getCHMax(self) -> float:
        """Retrieve the current value of CH_MAX.

        This call retrieves global parameter :attr:`~SlbmInterface.CH_MAX`.
        Alternatively, this parameter may be retrieved by calling it as an
        attribute of the current :class:`SlbmInterface` object.

        `c` is the Zhao `c` parameter, and `h` is the turning depth of the ray
        below the Moho. The Zhao method only valid for `c*h << 1`. When `c*h >
        CH_MAX`, then RSTT will throw an exception.

        Examples
        --------
            >>> slbm.getCHMax()

            >>> slbm.CH_MAX

        Returns
        -------
        float
            Global :attr:`~SlbmInterface.CH_MAX` parameter

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getCHMax()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getClassCount(self) -> str:
        """Retrieve a table that lists the number of instances of various RSTT
        classes that are currently instantiated.

        Very useful for debugging memory leaks.

        Examples
        --------
            >>> slbm.getClassCount()

        Returns
        -------
        str
            Table that lists the number of currently-initiated classes

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getClassCount()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getDelDepth(self) -> float:
        """Retrieve the value of step change in depth used to compute depth
        derivatives

        Examples
        --------
            >>> slbm.getDelDepth()

        Returns
        -------
        float
            Del depth, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getDelDepth()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getDelDistance(self) -> float:
        """Retrieve the value of step change in distance used to compute
        horizontal derivatives

        Examples
        --------
            >>> slbm.getDelDistance()

        Returns
        -------
        float
            Del distance, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getDelDistance()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getDistAz(self,
            lat1Rad: float, lon1Rad: float,
            lat2Rad: float, lon2Rad: float) -> Tuple[float, float]:
        """Compute distance and azimuth between two points.

        Computed distance will range between 0 and pi, and azimuth will range
        from -pi to pi.

        Examples
        --------
            >>> slbm.getDistAz(0.1, 0., 0.082, 0.)

        Parameters
        ----------
        lat1Rad : float
            Latitude of starting location, in radians
        lon1Rad : float
            Longitude of starting location, in radians
        lat2Rad : float
            Latitude of ending location, in radians
        lon2Rad : float
            Longitude of ending location, in radians

        Returns
        -------
        distance : float
            Distance between the two specified locations, in radians
        azimuth : float
            Azimuth between the two specified locations, in radians

        Raises
        ------
        TypeError
            Specified Lat/lon locations aren't all `float`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: locations are all floats
        if not all(isinstance(arg, float) for arg in (lat1Rad, lon1Rad, lat2Rad, lon2Rad)):
            raise TypeError("Location latitude/longitudes should all be type 'float'")

        # try and call the function
        try:
            return super().getDistAz(lat1Rad, lon1Rad, lat2Rad, lon2Rad)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getDistance(self) -> float:
        """Retrieve the source-receiver separation.

        Examples
        --------
            >>> slbm.getDistance()

        Returns
        -------
        float
            The Source-receiver separation, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getDistance()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getFractionActive(self) -> float:
        """Retrieve the fraction of the path length of the current `GreatCircle`
        object that is within the currently-defined active region.

        Examples
        --------
            >>> slbm.getFractionActive()

        Returns
        -------
        float
            Fraction of path length in active region

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getFractionActive()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGreatCircleData(self) -> Tuple[str, float,
            Tuple[float, ...], Tuple[float, ...],
            Tuple[float, ...], Tuple[float, ...],
            int, Tuple[float, ...], Tuple[float, ...]]:
        """Retrieve information about the great circle path.

        Retrieve information about the great circle path including the interface
        depths at source and receiver, the velocity profiles at the source and
        receiver, and mantle velocity and velocity gradient at points along the
        great circle path from source pierce point to receiver pierce point.

        The first horizontal segment starts at the source, the last horizontal
        segment ends at the receiver, and each one is of size
        `actual_path_increment`. The head wave velocities are interpolated at
        the center of each of these horizontal segments, just below the head
        wave interface.

        Examples
        --------
            >>> slbm.getGreatCircleData()

        Returns
        -------
        phase : str
            The phase supported by the current `GreatCircle`
        actual_path_increment : float
            Horizontal separation of the `LayerProfile` objects along the head
            wave interface, in radians
        sourceDepth : tuple of floats
            Depths of all the model interfaces below the source, in kilometers
        sourceVelocity : tuple of floats
            P or S velocity of each interval below the source, in kilometers
            per second
        receiverDepth : tuple of floats
            Depths of all the model interfaces below the receiver, in kilometers
        receiverVelocity : tuple of floats
            P or S velocity of each interval below the receiver, in kilometers
            per second
        npoints : int
            Nunber of points along the headwave path where velocity and gradient
            values are interpolated
        headWaveVelocity : tuple of floats
            P or S velocity at the center of each horizontal segment between the
            source and the receiver, in kilometers per seconds
        gradient : tuple of floats
            P or S velocity gradient in the mantle at the center of each
            horizontal segment of the head wave, in 1/seconds

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getGreatCircleData()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGreatCircleLocations(self) -> Tuple[Tuple[float, ...], Tuple[float, ...], Tuple[float, ...]]:
        """Retrieve the latitudes, longitudes and depths of all the profile
        positions along the headwave interface.

        Profile positions are located at the center of each segment of the head
        wave interface between the source and receiver. The first position is
        located `actual_path_increment`/2 radians from the source, the last
        profile position is located `actual_path_increment`/2 radians from the
        receiver, and the others are spaced `actual_path_increment` radians
        apart.

        Examples
        --------
            >>> slbm.getGreatCircleLocations()

        Returns
        -------
        latitude : tuple of floats
            Latitude at the center of each headwave segment, in radians
        longitude : tuple of floats
            Longitude at the center of each headwave segment, in radians
        depth : tuple of floats
            Depth of the headwave interface at the center of each headwave
            segment, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getGreatCircleLocations()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGreatCircleNodeInfo(self) -> Tuple[Tuple[Tuple[int, ...], ...], Tuple[Tuple[float, ...], ...]]:
        """Retrieve information about the interpolated points along the
        headwave path.

        Examples
        --------
            >>> slbm.getGreatCircleNodeInfo()

        Returns
        -------
        neighbors : tuple of tuples of ints
            Ragged 2D array of `ints` with dimensions `npoints` x `nnodes`
            containing the `nodeIds` of the neighboring grid nodes used to
            derive the interpolated data at each head wave profile
        coefficients : tuple of tuples of doubles
            Ragged 2D array of `doubles` with dimensions `npoints` x `nnodes`
            containing the interpolation coefficients applied to each element
            of `neighbors`

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getGreatCircleNodeInfo()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGreatCirclePoints(self,
            lat1Rad: float, lon1Rad: float,
            lat2Rad: float, lon2Rad: float,
            npoints: int) -> Tuple[Tuple[float, ...], Tuple[float, ...]]:
        """Retrieve an array of latitude/longitude points along a great circle
        path between two specified points.

        The great circle path between the two points is divided into `npoints-1`
        equal size cells and the computed points are located at the boundaries
        of those cells. First point will coincide with the startnig point and
        last point with the ending point.

        Examples
        --------
            >>> slbm.getGreatCirclePoints(0.1, 0., 0.082, 0., 10)

        Parameters
        ----------
        lat1Rad : float
            Latitude of starting location, in radians
        lon1Rad : float
            Longitude of starting location, in radians
        lat2Rad : float
            Latitude of ending location, in radians
        lon2Rad : float
            Longitude of ending location, in radians
        npoints : int
            The desired number of points along the great circle

        Returns
        -------
        latitudes : tuple of floats
            The latitudes of the points along the great circle, in radians
        longitudes : tuple of floats
            The longitudes of the points along the great circle, in radians

        Raises
        ------
        TypeError
            Specified Lat/lon locations aren't all `float`
        ValueError
            An inappropriate number of points was requested
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: locations are all floats
        if not all(isinstance(arg, float) for arg in (lat1Rad, lon1Rad, lat2Rad, lon2Rad)):
            raise TypeError("Location latitude/longitudes should all be type 'float'")

        # ARG CHECK: number of requested points is >= 2
        if not npoints >= 2:
            raise ValueError("`npoints` must be at least 2")

        # try and call the function
        try:
            return super().getGreatCirclePoints(lat1Rad, lon1Rad, lat2Rad, lon2Rad, npoints)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGreatCirclePointsOnCenters(self,
            lat1Rad: float, lon1Rad: float,
            lat2Rad: float, lon2Rad: float,
            npoints: int) -> Tuple[Tuple[float, ...], Tuple[float, ...]]:
        """Retrieve an array of latitude/longitude points along a great circle
        path between two specified points.

        The great circle path between the two points is divided into `npoints-1`
        equal size cells and the computed points are located at the centers of
        those cells. First point will coincide with the startnig point and last
        point with the ending point.

        Examples
        --------
            >>> slbm.getGreatCirclePointsOnCenters(0.1, 0., 0.082, 0., 10)

        Parameters
        ----------
        lat1Rad : float
            Latitude of starting location, in radians
        lon1Rad : float
            Longitude of starting location, in radians
        lat2Rad : float
            Latitude of ending location, in radians
        lon2Rad : float
            Longitude of ending location, in radians
        npoints : int
            The desired number of points along the great circle

        Returns
        -------
        latitudes : tuple of floats
            The latitudes of the points along the great circle, in radians
        longitudes : tuple of floats
            The longitudes of the points along the great circle, in radians

        Raises
        ------
        TypeError
            Specified Lat/lon locations aren't all `float`
        ValueError
            An inappropriate number of points was requested
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: locations are all floats
        if not all(isinstance(arg, float) for arg in (lat1Rad, lon1Rad, lat2Rad, lon2Rad)):
            raise TypeError("Location latitude/longitudes should all be type 'float'")

        # ARG CHECK: number of requested points is >= 2
        if not npoints >= 2:
            raise ValueError("`npoints` must be at least 2")

        # try and call the function
        try:
            return super().getGreatCirclePointsOnCenters(lat1Rad, lon1Rad, lat2Rad, lon2Rad, npoints)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGridData(self, nodeId: int) -> Tuple[float, float,
            Tuple[float,...], Tuple[float,...], Tuple[float,...], Tuple[float,...]]:
        """Retrieve information associated with a specified node in the
        velocity grid.

        Retrieve the latitude, longitude, interface depths, P and S wave
        interval velocities and P and S mantle gradient information associated
        with a specified node in the velocity grid.

        Examples
        --------
            >>> slbm.getGridData(1001)

        Parameters
        ----------
        nodeId: int
            Node ID of the grid point in the model (zero based index)

        Returns
        -------
        latitude : float
            Latitude of the active node, in radians
        longitude : float
            Longitude of the active node, in radians
        depth : tuple of floats
            Depths of all the model interfaces, in kilometers
        pvelocity : tuple of floats
            P velocities of the intervals at the active node, in kilometers per second
        svelocity : tuple of floats
            S velocities of the intervals at the active node, in kilometers per second
        gradient : tuple of floats
            P and S velocity gradients in the mantle, in 1/second

        Raises
        ------
        TypeError
            `nodeId` isn't an `int`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # phase is an int or string
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # try and call the function
        try:
            return super().getGridData(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getGridNodeId(self, activeNodeId: int) -> int:
        """Retrieve the grid node ID that corresponds to a specified active node ID.

        Examples
        --------
            >>> slbm.getGridNodeId(11)

        Returns
        -------
        int
            Grid node ID

        Raises
        ------
        TypeError
            Provided node ID isn't `int`
        ValueError
            An inappropriate node ID was requested
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: activeNodeId is an int
        if not isinstance(activeNodeId, int):  # activeNodeId is an int
            raise TypeError("`activeNodeId` expects type 'int', received '{}'".format(type(activeNodeId).__name__))

        # ARG CHECK: activeNodeId >= 0
        if not activeNodeId >= 0:
            raise ValueError("`activeNodeId` must be greater than or equal to 0")

        # try and call the function
        try:
            return super().getGridNodeId(activeNodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getHeadwaveDistance(self) -> float:
        """Retrieve the angular distance traveled by the ray below the headwave
        interface.

        This is the total distance minus the horizontal offsets below the source
        and receiver. :meth:`~SlbmInterface.getSourceDistance`
        + :meth:`~SlbmInterface.getReceiverDistance`
        + :meth:`~SlbmInterface.getHeadwaveDistance`
        = :meth:`~SlbmInterface.getDistance`.

        Examples
        --------
            >>> slbm.getHeadwaveDistance()

        Returns
        -------
        float
            Angular distance traveled by the ray below the headwave interface,
            in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getHeadwaveDistance()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getHeadwaveDistanceKm(self) -> float:
        """Retrieve the horizontal distance traveled by the ray below the
        headwave interface.

        This is the sum of `actual_path_increment(i) * R(i)` where
        `actual_path_increment(i)` is the angular distance traveled by the ray
        in each angular distance increment along the head wave interface, and
        `R(i)` is the radius of the head wave interface in that same horizontal
        increment.

        Examples
        --------
            >>> slbm.getHeadwaveDistanceKm()

        Returns
        -------
        float
            Horizontal distance traveled by the ray below the headwave
            interface, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getHeadwaveDistanceKm()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getInterpolatedPoint(self, lat: float, lon: float) -> Tuple[Tuple[int, ...],
        Tuple[float, ...], Tuple[float, ...], Tuple[float, ...], Tuple[float, ...],
        float, float]:
        """Retrieve interpolated data from the earth model at a single specified
        latitude/longitude.

        Examples
        --------
            >>> slbm.getInterpolatedPoint(0.1, 0.2)

        Parameters
        ----------
        lat : float
            Latitude where information is to be interpolated, in radians
        lon : float
            Longitude where information is to be interpolated, in radians

        Returns
        -------
        nodeIds : tuple of ints
            Node IDs of the grid nodes that were involved in the interpolation
        coefficients : tuple of floats
            Interpolation coefficients that were applied to the information from
            the neighboring grid nodes
        depth : tuple of floats
            Depths of the tops of all the model interfaces, in kilometers
        pvelocity : tuple of floats
            P velocities of each layer of the model, in kilometers per second
        svelocity : tuple of floats
            S velocities of each layer of the model, in kilometers per second
        pgradient : float
            P velocity gradient in the mantle, in 1/second
        sgradient : float
            S velocity gradient in the mantle, in 1/second

        Raises
        ------
        TypeError
            Latitude/longitude aren't type `float`
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: lat/lon are floats
        if not all(isinstance(arg, float) for arg in (lat, lon)):
            raise TypeError("Latitude/longitude should be type 'float'")

        # try and call the function
        try:
            return super().getInterpolatedPoint(lat, lon)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getInterpolatedTransect(self,
            lat: Tuple[float, ...], lon: Tuple[float, ...]) -> Tuple[Tuple[Tuple[int, ...]],
            Tuple[Tuple[float, ...]], Tuple[Tuple[float, ...]],
            Tuple[Tuple[float, ...]], Tuple[Tuple[float, ...]], 
            Tuple[float, ...], Tuple[float, ...], int]:
        """Retrieve interpolated data from the earth model along a transec
        defined by equal sized, 1D arrays of latitude and longitude.

        Examples
        --------
            >>> slbm.getInterpolatedTransect()

        Parameters
        ----------
        lat : tuple of floats
            Latitudes along the transect, in radians
        lon : tuple of floats
            Longitudes along the transect, in radians

        Returns
        -------
        nodeId : tuple of tuple of ints
            Node IDs of the grid nodes that were involved in the interpolations
        coefficients : tuple of tuple of floats
            Interpolation coefficients that were applied to the information from
            the neighboring grid nodes
        depth : tuple of tuple of floats
            Depth of the tops of the interfaces in the model, in kilometers
        pvelocity : tuple of tuple of floats
            P velocities of each layer of the model, in kilometers per second
        svelocity : tuple of tuple of floats
            S velocities of each layer of the model, in kilometers per second
        pgradient : tuple of floats
            Mantle P velocity gradient, in 1/seconds
        sgradient : tuple of floats
            Mantle S velocity gradient, in 1/sec
        nInvalid : int
            Number of points that were out of the model range

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getInterpolatedTransect(lat, lon)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getInterpolatorType(self) -> str:
        """Retrieve the type of interpolator currently in use; either "LINEAR"
        or "NATURAL_NEIGHBOR".

        Examples
        --------
            >>> slbm.getInterpolatorType()

        Returns
        -------
        str
            Type of interpolator currently in use

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getInterpolatorType()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getMaxDepth(self) -> float:
        """Retrieve the current value for the maximum source depth.

        Examples
        --------
            >>> slbm.getMaxDepth()

        Returns
        -------
        float
            Maximum source depth, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getMaxDepth()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getMaxDistance(self) -> float:
        """Retrieve the current value for the maximum source-receiver separation.

        Examples
        --------
            >>> slbm.getMaxDistance()

        Returns
        -------
        float
            Maximum source-receiver separation, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getMaxDistance()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getModelPath(self) -> str:
        """Return the path to the RSTT model.

        Examples
        --------
            >>> slbm.getModelPath()

        Returns
        -------
        str
            Path to the RSTT model

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getModelPath()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getModelString(self) -> str:
        """Calls :meth:`~SlbmInterface.toString` on the RSTT model.

        Examples
        --------
            >>> slbm.getModelString()

        Returns
        -------
        str
            Human-readable string representation of the RSTT model

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getModelString()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNActiveNodes(self) -> int:
        """Retrieve the number of active nodes in the `Grid`.

        Examples
        --------
            >>> slbm.getNActiveNodes()

        Returns
        -------
        int
            Number of active nodes in the `Grid`

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getNActiveNodes()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNGridNodes(self) -> int:
        """Retrieve the number of `Grid` nodes in the Earth model.

        Examples
        --------
            >>> slbm.getNGridNodes()

        Returns
        -------
        str
            Returns something

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getNGridNodes()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNHeadWavePoints(self) -> int:
        """Retrieve the number of `LayerProfile` objects positioned along the
        head wave interface.

        Examples
        --------
            >>> slbm.getNHeadWavePoints()

        Returns
        -------
        int
            Number of `LayerProfile` objects positioned along the head wave
            interface

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getNHeadWavePoints()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNodeAzimuth(self, node1: int, node2: int) -> float:
        """Retrieve the azimuth from `node1` to `node2`.

        Examples
        --------
            >>> slbm.getNodeAzimuth(123, 1001)

        Parameters
        ----------
        node1 : int
            ID of starting node
        node2 : int
            ID of ending node

        Returns
        -------
        float
            Azimuth from `node1` to `node2`

        Raises
        ------
        TypeError
            Specified node IDs aren't type `int`
        ValueError
            Inappropriate node IDs were supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodes are all ints
        if not all(isinstance(arg, int) for arg in (node1, node2)):
            raise TypeError("Node IDs should all be type 'int'")

        # ARG CHECK: nodeids >= 0
        if not all([node >= 0 for node in (node1, node2)]):
            raise ValueError("Node IDs must be greater than or equal to zero")

        # try and call the function
        try:
            return super().getNodeAzimuth(node1, node2)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNodeHitCount(self, nodeId: int) -> int:
        """Retrieve the number of times that the specified node has been
        'touched' by a `GreatCircle` object.

        The hit count of each node is initialized in the
        :meth:`~SlbmInterface.loadVelocityModel` method. Every time the
        :meth:`~SlbmInterface.getWeights` method is called for a particular `GreatCircle` object,
        all the `nodeIds` that contribute any `weight` to that `GreatCircle`
        object have their hit count incremented by one.

        Examples
        --------
            >>> slbm.getNodeHitCount(1001)

        Parameters
        ----------
        nodeId : int
            Node for which to query the hit count

        Returns
        -------
        int
            Number of times that the specified node has been 'touched'

        Raises
        ------
        TypeError
            Specified node ID isn't type `int`
        ValueError
            Inappropriate node ID was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: node is an int
        if not isinstance(nodeId, int):
            raise TypeError("Node ID should be type 'int'")

        # ARG CHECK: nodeId >= 0
        if not nodeId >= 0:
            raise ValueError("Node ID must be greater than or equal to zero")

        # try and call the function
        try:
            return super().getNodeHitCount(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNodeNeighborInfo(self, nodeId: int) -> Tuple[Tuple[int, ...],
            Tuple[float, ...], Tuple[float, ...]]:
        """Retrieve the IDs of the nodes that surround the specified node.

        Examples
        --------
            >>> slbm.getNodeNeighborInfo(1001)

        Returns
        -------
        neighbors : tuple of ints
            Neighbors of the specified node
        distance : tuple of floats
            Distance of the neighbors to the specified node
        azimuth : tuple of floats
            Azimuth of the neighbors to the specified node

        Raises
        ------
        TypeError
            Specified node ID isn't type `int`
        ValueError
            Inappropriate node ID was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: node is an int
        if not isinstance(nodeId, int):
            raise TypeError("Node ID should be type 'int'")

        # ARG CHECK: nodeId >= 0
        if not nodeId >= 0:
            raise ValueError("Node ID must be greater than or equal to zero")

        # try and call the function
        try:
            return super().getNodeNeighborInfo(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNodeNeighbors(self, nodeId: int) -> Tuple[int, ...]:
        """Retrieve the IDs of the nodes that surround the specified node.

        Examples
        --------
            >>> slbm.getNodeNeighbors(1001)

        Returns
        -------
        int
            Returns something

        Raises
        ------
        TypeError
            Specified node ID isn't type `int`
        ValueError
            Inappropriate node ID was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: node is an int
        if not isinstance(nodeId, int):
            raise TypeError("Node ID should be type 'int'")

        # ARG CHECK: nodeId >= 0
        if not nodeId >= 0:
            raise ValueError("Node ID must be greater than or equal to zero")

        # try and call the function
        try:
            return super().getNodeNeighbors(nodeId)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getNodeSeparation(self, node1: int, node2: int) -> float:
        """Retrieve the angular separation of two grid nodes.

        Examples
        --------
            >>> slbm.getNodeSeparation(123, 1001)

        Returns
        -------
        float
            Angular separation of `node1` and `node2`, in radians

        Raises
        ------
        TypeError
            Specified node IDs aren't type `int`
        ValueError
            Inappropriate node IDs were supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodes are all ints
        if not all(isinstance(arg, int) for arg in (node1, node2)):
            raise TypeError("Node IDs should all be type 'int'")

        # ARG CHECK: nodeids >= 0
        if not all([node >= 0 for node in (node1, node2)]):
            raise ValueError("Node IDs must be greater than or equal to zero")

        # try and call the function
        try:
            return super().getNodeSeparation()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getPathIncrement(self) -> float:
        """Retrieve the current value of the spacing of great circle nodes along
        the head wave interface.

        The actual spacing will be reduced from the requested value in order
        that an integral number of equally spaced `LayerProfile` objects will
        exactly span the source-receiver separation.

        The default value is 0.1 degrees.

        Examples
        --------
            >>> slbm.getPathIncrement()

        Returns
        -------
        float
            Spacing of the great circle nodes along the head wave interface,
            in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getPathIncrement()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getPgLgComponents(self):
        """Retrieve information about Pg/Lg travel time calculations.

        This method only returns useful information when the phase is `Pg` or `Lg.`

        `tTotal` will be exactly equal to the lesser of `tTaup` or `tHeadwave`.

        Examples
        --------
            >>> slbm.getPgLgComponents()

        Returns
        -------
        tTotal : float
            Total travel time, in seconds
        tTaup : float
            TauP travel time, in seconds
        tHeadwave : float
            Headwave travel time, in seconds
        pTaup : float
            TauP ray parameter
        pHeadwave : float
            Headwave ray parameter
        trTaup : float
            Radius at which the taup ray turned, in kilometers
        trHeadwave : float
            Radius at which the headwave ray turned, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getPgLgComponents()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getPhase(self) -> str:
        """Retrieve the phase specified in last call to
        :meth:`~SlbmInterface.createGreatCircle`.

        Examples
        --------
            >>> slbm.getPhase()

        Returns
        -------
        str
            The phase specified in last call to :meth:`~SlbmInterface.createGreatCircle`

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getPhase()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getPiercePointReceiver(self) -> Tuple[float, float, float]:
        """Retrieve the location of the Moho pierce point below the receiver.

        For Pg, Lg an exception is thrown.

        Examples
        --------
            >>> slbm.getPiercePointReceiver()

        Returns
        -------
        latitude : float
            Latitude of the Moho pierce point below the receiver, in radians
        longitude : float
            Longitude of the Moho pierce point below the receiver, in radians
        depth : float
            Depth of the Moho pierce point below the receiver, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getPiercePointReceiver()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getPiercePointSource(self):
        """Retrieve the location of the Moho pierce point below the source.

        For Pg, Lg an exception is thrown.

        Examples
        --------
            >>> slbm.getPiercePointReceiver()

        Returns
        -------
        latitude : float
            Latitude of the Moho pierce point below the source, in radians
        longitude : float
            Longitude of the Moho pierce point below the source, in radians
        depth : float
            Depth of the Moho pierce point below the source, in kilometers

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getPiercePointSource()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getRayParameter(self) -> float:
        """Retrieve the ray parameter.

        Examples
        --------
            >>> slbm.getRayParameter()

        Returns
        -------
        float
            Ray parameter

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getRayParameter()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getReceiverDistance(self) -> float:
        """Retrieve horizontal offset below the receiver.

        This is the angular distance between the location of the receiver and
        the receiver pierce point where the ray impinged on the headwave
        interface.

        Examples
        --------
            >>> slbm.getReceiverDistance()

        Returns
        -------
        float
            Horizontal offset below the receiver, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getReceiverDistance()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getSlowness(self) -> float:
        """Retrieve the horizontal slowness (i.e., the derivative of travel time
        with respect to receiver-source distance).

        Examples
        --------
            >>> slbm.getSlowness()

        Returns
        -------
        float
            Horizontal slownessm in seconds/radian

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getSlowness()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getSlownessUncertainty(self) -> float:
        """Retrieve uncertainty of the horizontal slowness using the phase and
        distance specified in last call to :meth:`~SlbmInterface.getGreatCircle`.

        Examples
        --------
            >>> slbm.getSlownessUncertainty()

        Returns
        -------
        float
            Uncertainty of the horizontal slowness, in seconds per radian

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getSlownessUncertainty()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getSourceDistance(self) -> float:
        """Retrieve horizontal offset below the source.

        This is the angular distance between the location of the source and
        the source pierce point where the ray impinged on the headwave
        interface.

        Examples
        --------
            >>> slbm.getSourceDistance()

        Returns
        -------
        float
            Horizontal offset below the source, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getSourceDistance()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getTessId(self) -> str:
        """Retrieve the tessellation ID of the model currently in memory.

        Examples
        --------
            >>> slbm.getTessId()

        Returns
        -------
        str
            Tessellation ID of the model currently in memory

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getTessId()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getTravelTime(self) -> float:
        """Retrieve the total travel time for the `GreatCircle`.

        Examples
        --------
            >>> slbm.getTravelTime()

        Returns
        -------
        float
            Total travel time for the `GreatCircle`, in seconds

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getTravelTime()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getTravelTimeComponents(self) -> Tuple[float, float, float, float, float]:
        """Retrieve the total travel time and the four components that
        contribute to it for the current GreatCircle.

        Examples
        --------
            >>> slbm.getTravelTimeComponents()

        Returns
        -------
        tTotal : float
            Total travel time, in seconds
        tSource : float
            Crustal travel time below the source, in seconds
        tReceiver : float
            Crustal travel time below the receiver, in seconds
        tHeadwave : float
            Head wave travel time, in seconds
        tGradient : float
            Zhao gradient correction term, in seconds

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getTravelTimeComponents()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getTravelTimeUncertainty(self, useRandomError: bool = False) -> float:
        """Returns the path-dependent travel time uncertainty (PDU), in seconds

        Returns the path-dependent travel time uncertainty (PDU) for the
        `GreatCircle`, in seconds. Path-dependent uncertainty is computed
        with *model error*, *bias*, and (optionally) *random error* (Begnaud
        et al., 2020). By default, *random error* is not used in the
        computation.

        Examples
        --------
            >>> slbm.getTravelTimeUncertainty()
            3.9911

            Use the *random error* values in the uncertainty calculation

            >>> slbm.getTravelTimeUncertainty(True)
            4.0463

        Parameters
        ----------
        useRandomError : bool
            Determines whether or not *random error* is used in the travel time
            uncertainty computation.

        Returns
        -------
        float
            Returns the path-dependent travel time uncertainty (PDU), in seconds

        Raises
        ------
        TypeError
            `useRandomError` is not a a `bool`, or too many arguments were supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # some error checking
        if not isinstance(useRandomError, bool):  # verbosity is an int
            raise TypeError("`useRandomError` expects type 'bool', received '{}'".format(type(useRandomError).__name__))

        # try and call the function
        try:
            return super().getTravelTimeUncertainty(useRandomError)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e

    # alias path-dependent `getTravelTimeUncertainty` to `getTravelTimeUncertaintyPDU`
    getTravelTimeUncertaintyPDU = getTravelTimeUncertainty


    def getTravelTimeUncertainty1D(self) -> float:
        """Returns the path-independent travel time uncertainty (PIU), in seconds

        Returns the path-independent travel time uncertainty (PIU) for the
        `GreatCircle`, in seconds. This was the standard uncertainty computation
        prior to RSTT v3.1.0.

        Examples
        --------
            >>> slbm.getTravelTimeUncertainty()
            1.1542

        Returns
        -------
        float
            Returns the path-independent travel time uncertainty (PIU), in seconds

        Raises
        ------
        TypeError
            Too many arguments were supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getTravelTimeUncertainty1D()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e

    # alias path-independent `getTravelTimeUncertainty1D` to `getTravelTimeUncertaintyPIU`
    getTravelTimeUncertaintyPIU = getTravelTimeUncertainty1D


    def getTurningRadius(self) -> float:
        """Retrieve the turning radius of the ray.

        Examples
        --------
            >>> slbm.getTurningRadius()

        Returns
        -------
        float
            Turning radius of the ray

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getTurningRadius()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getUncertaintyFileFormat(self, phase: int or str, attribute: int or str) -> str:
        """Return path-independent uncertainty information related to the
        specified `phase` and `attribute` in the format of an ASCII model.

        Examples
        --------
            >>> slbm.getUncertaintyFileFormat(0, 1)

            >>> slbm.getUncertaintyFileFormat('Pn', 'SH')

        Parameters
        ----------
        phase : int or str
            A phase name, or associated number. Accepted values are
                * `Pn` or `0`
                * `Sn` or `1`
                * `Pg` or `2`
                * `Lg` or `3`
        attribute : int or str
            An attribute name, or associated number. Accepted values are
                * `TT` or `0`
                * `SH` or `1`
                * `AZ` or `2`

        Returns
        -------
        str
            Path-independent uncertainty information related to the specified
            `phase` and `attribute`.

        Raises
        ------
        TypeError
            `phase` or `attribute` aren't an `int` or a `str`
        ValueError
            An inappropriate `phase` or `attribute` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: phase is an int or str
        if not isinstance(phase, (int, str)):  # phase is an int or string
            raise TypeError("`phase` expects type 'int' or 'str', received '{}'".format(type(phase).__name__))

        # ARG CHECK: str phase is one of [Pn, Sn, Pg, Lg]
        if isinstance(phase, str):
            if phase.lower() not in ('pn', 'sn', 'pg', 'lg'):
                raise ValueError("`phase` must be one of: 'Pn', 'Sn', 'Pg', or 'Lg'")

        # ARG CHECK: int phase is one of [0, 1, 2, 3]
        if isinstance(phase, int):
            if phase not in (0, 1, 2, 3):
                raise ValueError("`phase` must be one of: 0 (Pn), 1 (Sn), 2 (Pg), or 3 (Lg)")

        # ARG CHECK: attribute is an int or str
        if not isinstance(attribute, (int, str)):  # attribute is an int or string
            raise TypeError("`attribute` expects type 'int' or 'str', received '{}'".format(type(attribute).__name__))

        # ARG CHECK: str attribute is one of [TT, SH, AZ]
        if isinstance(attribute, str):
            if attribute.lower() not in ('tt', 'sh', 'az'):
                raise ValueError("`phase` must be one of: 'TT', 'SH', or 'AZ'")

        # ARG CHECK: int attribute is one of [0, 1, 2]
        if isinstance(attribute, int):
            if attribute not in (0, 1, 2):
                raise ValueError("`attribute` must be one of: 0 (TT), 1 (SH), or 2 (AZ)")

        # convert str phase and attribute to ints
        if isinstance(phase, str):
            phase = phases(phase)
        if isinstance(attribute, str):
            attribute = attributes(attribute)

        # try and call the function
        try:
            return super().getUncertaintyFileFormat(phase, attribute)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getUncertaintyTable(self, phase: int or str, attribute: int or str) -> str:
        """Return path-independent uncertainty information related to the
        specified `phase` and `attribute` in a table format.

        Examples
        --------
            >>> slbm.getUncertaintyTable(0, 1)

            >>> slbm.getUncertaintyTable('Pn', 'SH')

        Parameters
        ----------
        phase : int or str
            A phase name, or associated number. Accepted values are
                * `Pn` or `0`
                * `Sn` or `1`
                * `Pg` or `2`
                * `Lg` or `3`
        attribute : int or str
            An attribute name, or associated number. Accepted values are
                * `TT` or `0`
                * `SH` or `1`
                * `AZ` or `2`

        Returns
        -------
        str
            Path-independent uncertainty information related to the specified
            `phase` and `attribute`.

        Raises
        ------
        TypeError
            `phase` or `attribute` aren't an `int` or a `str`
        ValueError
            An inappropriate `phase` or `attribute` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: phase is an int or str
        if not isinstance(phase, (int, str)):  # phase is an int or string
            raise TypeError("`phase` expects type 'int' or 'str', received '{}'".format(type(phase).__name__))

        # ARG CHECK: str phase is one of [Pn, Sn, Pg, Lg]
        if isinstance(phase, str):
            if phase.lower() not in ('pn', 'sn', 'pg', 'lg'):
                raise ValueError("`phase` must be one of: 'Pn', 'Sn', 'Pg', or 'Lg'")

        # ARG CHECK: int phase is one of [0, 1, 2, 3]
        if isinstance(phase, int):
            if phase not in (0, 1, 2, 3):
                raise ValueError("`phase` must be one of: 0 (Pn), 1 (Sn), 2 (Pg), or 3 (Lg)")

        # ARG CHECK: attribute is an int or str
        if not isinstance(attribute, (int, str)):  # attribute is an int or string
            raise TypeError("`attribute` expects type 'int' or 'str', received '{}'".format(type(attribute).__name__))

        # ARG CHECK: str attribute is one of [TT, SH, AZ]
        if isinstance(attribute, str):
            if attribute.lower() not in ('tt', 'sh', 'az'):
                raise ValueError("`phase` must be one of: 'TT', 'SH', or 'AZ'")

        # ARG CHECK: int attribute is one of [0, 1, 2]
        if isinstance(attribute, int):
            if attribute not in (0, 1, 2):
                raise ValueError("`attribute` must be one of: 0 (TT), 1 (SH), or 2 (AZ)")

        # convert str phase and attribute to ints
        if isinstance(phase, str):
            phase = phases(phase)
        if isinstance(attribute, str):
            attribute = attributes(attribute)

        # try and call the function
        try:
            return super().getUncertaintyTable(phase, attribute)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getWeights(self) -> Tuple[Tuple[int, ...], Tuple[float, ...]]:
        """Retrieve the weight assigned to each grid node that was touched by
        the `GreatCircle`.

        Each grid node is included only once, even though more than one
        `LayerProfile` object may have contributed some weight to it. The sum of
        all the weights will equal the horizontal distance traveled by the ray
        along the head wave interface, from the source pierce point to the
        receiver pierce point, in kilometers.

        Note: This method returns active node IDs, not grid node IDs. if a grid
        node has weight but is not an active node, the node ID will be -1.

        Examples
        --------
            >>> slbm.getWeights()

        Returns
        -------
        nodeId : tuple of ints
            Active node IDs of all the grid nodes touched by the current `GreatCircle`
        weights : tuple of floats
            Weights of all the grid nodes touched by the current `GreatCircle`

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getWeights()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getWeightsReceiver(self) -> Tuple[Tuple[int, ...], Tuple[float, ...]]:
        """Retrieve the node IDs and the interpolation coefficients for the
        receiver `CrustalProfile`.

        For linear interpolation the number of weights will equal 3, but for
        natural neighbor interpolation it will be variable but less than 10. The
        sum of the weights will equal 1.

        Examples
        --------
            >>> slbm.getWeightsReceiver()

        Returns
        -------
        nodeId : tuple of ints
            Active node IDs of all the grid nodes touched by the current `GreatCircle`
        weights : tuple of floats
            Weights of all the grid nodes touched by the current `GreatCircle`

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getWeightsReceiver()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getWeightsSource(self) -> Tuple[Tuple[int, ...], Tuple[float, ...]]:
        """Retrieve the node IDs and the interpolation coefficients for the
        source `CrustalProfile`.

        For linear interpolation the number of weights will equal 3, but for
        natural neighbor interpolation it will be variable but less than 10. The
        sum of the weights will equal 1.

        Examples
        --------
            >>> slbm.getWeightsSource()

        Returns
        -------
        nodeId : tuple of ints
            Active node IDs of all the grid nodes touched by the current `GreatCircle`
        weights : tuple of floats
            Weights of all the grid nodes touched by the current `GreatCircle`

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getWeightsSource()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def getZhaoParameters(self) -> Tuple[float, float, float, float, float, int]:
        """Retrieve some of the parameters that contribute to the calculation
        of total travel time using the Zhao algorithm.

        This method only returns meaningful results for phases Pn and Sn.

        Examples
        --------
            >>> slbm.getZhaoParameters()

        Returns
        -------
        Vm : float
            Velocity at the top of the mantle, averaged along the Moho between
            the source and receiver pierce points
        Gm : float
            Velocity gradient at the top of the mantle, averaged along the Moho
            between the source and receiver pierce points
        H : float
            Turning depth of the ray relative to the Moho
        C : float
            Constant whose product with `V0` gives the mantle velocity gradient
            for a flat Earth (`V0` is the velocity of the top of the mantle
            averaged over the whole model)
        Cm : float
            Constant whose product with `Vm` gives the mantle velocity gradient
            for a flat Earth
        udSign : int
            Value indicates:
                * 0, the source is in the crust
                * +1, the ray leaves a mantle source in the downgoing direction
                * -1, the ray leaves a mantle source in an upgoing direction

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().getZhaoParameters()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def get_dtt_ddepth(self) -> float:
        """Retrieve the derivative of travel time with respect to source depth.

        Long description

        Examples
        --------
            >>> slbm.get_dtt_ddepth()

        Returns
        -------
        float
            Derivative of travel time with respect to source depth, in seconds
            per kilometer

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().get_dtt_ddepth()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def get_dtt_ddist(self) -> float:
        """Retrieve the horizontal slowness, i.e., the derivative of travel time
        with respect to receiver-source distance.

        Long description

        Examples
        --------
            >>> slbm.get_dtt_ddepth()

        Returns
        -------
        float
            Horizontal slowness, in seconds per radian

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().get_dtt_ddist()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def get_dtt_dlat(self) -> float:
        """Retrieve the derivative of travel time with respect to source latitude.

        Examples
        --------
            >>> slbm.get_dtt_dlat()

        Returns
        -------
        float
            Derivative of travel time with respect to source latitude, in
            seconds per radian

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().get_dtt_dlat()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def get_dtt_dlon(self) -> float:
        """Retrieve the derivative of travel time with respect to source longitude.

        Examples
        --------
            >>> slbm.get_dtt_dlon()

        Returns
        -------
        float
            Derivative of travel time with respect to source longitude, in
            seconds per radian

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().get_dtt_dlon()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def initializeActiveNodes(self,
            latMinRad: float, lonMinRad: float,
            latMaxRad: float, lonMaxRad: float) -> None:
        """Set grid nodes within a latitude/longitude range as active nodes.

        Active nodes are defined as follows: for each triangle in the
        tessellation, if any of the 3 nodes that define the triangle is within
        the range specified by this method, then all 3 nodes are defined to be
        active nodes. Lats and lons must be specified in radians.

        Examples
        --------
            >>> slbm.initializeActiveNodes(0., 0., 0.1, 0.1)

        Parameters
        ----------
        latMinRad : float
            Minimum latitude, in radians
        lonMinRad : float
            Minimum longitude, in radians
        latMaxRad : float
            Maximum latitude, in radians
        lonMaxRad : float
            Maximum longitude, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: locations are all floats
        if not all(isinstance(arg, float) for arg in (latMinRad, lonMinRad, latMaxRad, lonMaxRad)):
            raise TypeError("Latitudes/longitudes should all be type 'float'")

        # try and call the function
        try:
            return super().initializeActiveNodes(latMinRad, lonMinRad, latMaxRad, lonMaxRad)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def isValid(self) -> bool:
        """Returns true if a `GreatCircle` object has been instantiated and is
        ready to be interrogated.

        Examples
        --------
            >>> slbm.isValid()

        Returns
        -------
        bool
            True if a `GreatCircle` object has been instantiated and is ready
            to be interrogated.

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().isValid()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def loadVelocityModel(self, model_path: str) -> None:
        """Load the velocity model into memory from the specified file or directory

        Load the velocity model into memory from the specified file or directory.

        Examples
        --------
            >>> slbm.loadVelocityModel("../models/example.geotess")

        Parameters
        ----------
        model_path : str
            Path to RSTT model, e.g., `/path/to/modelfile.geotess`. Relative
            path names are accepted.

        Raises
        ------
        TypeError
            `model_path` is not a `str`, or too many arguments were supplied
        FileNotFoundError
            The specified `model_path` was not found 
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: model_path is a str
        if not isinstance(model_path, str):
            raise TypeError("`model_path` expects type 'str', received '{}'".format(type(model_path).__name__))

        # ARG CHECK: model_path exists
        if not os.path.exists(model_path):
            raise FileNotFoundError("File does not exist: {}".format(model_path))

        # try and call the function
        try:
            super().loadVelocityModel(model_path)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def movePoint(self, lat1: float, lon1: float,
            distance: float, azimuth: float) -> Tuple[float, float]:
        """Find point B that is the specified distance and azimuth from point A.

        Examples
        --------
            >>> slbm.movePoint(0., 0., .1, 0.)

        Parameters
        ----------
        lat1 : float
            Latitude of point A, in radians
        lon1 : float
            longitude of point A, in radians
        distance : float
            Angular distance from point A to point B, in radians
        azimuth : float
            Azimuth from pointA to point B, clockwise from north, in radians

        Returns
        -------
        lat2 : float
            Latitude of point B, in radians
        lon2 : float
            longitude of point B, in radians

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # try and call the function
        try:
            return super().movePoint()

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def saveVelocityModel(self, modelFileName: str, modelFormat: int = 4) -> None:
        """Save the velocity model currently in memory to the specified file or
        directory.

        The following `formats` are supported:

            1. SLBM version 1 ascii file. All model information is output to a
               single file in ascii format. This format was available in SLBM
               version 2, but never used.

            2. SLBM version 2 directory format. Model information is output to
               a number of different files and directories, mostly in binary
               format. This format was used almost exclusively in SLBM version 2.

            3. SLBM version 3 directory format. Model information is output to
               a number of different files and directories, mostly in binary
               format. This format is very similar to format 2 with the
               difference being that the model tessellation and values are
               stored in GeoTess format instead of the custom SLBM format.

            4. SLBM version 4 single-file format. **This is the default and
               preferred format.** All model information is written to a single
               file. If the `modelFileName` extension is `.ascii` the file is
               written in ascii format, otherwise it is written in binary
               format.

        See `SLBM_Design.pdf` in the main documentation directory for detailed
        information about model output formats. Models stored in SLBM version 1
        and 2 formats (formats 1 and 2) only support linear interpolation.
        Models stored in SLBM version 3 formats (formats 3 and 4) support both
        linear and natural neighbor interpolation.

        Examples
        --------
            >>> slbm.saveVelocityModel("example.geotess")

            >>> slbm.saveVelocityModel("example.geotess", 4)

        Parameters
        ----------
        modelFileName : str
            Full or relative path to the file or directory to which the earth
            model is to be written
        modelFormat : int
            File format version of the output (default = 4)

        Raises
        ------
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: modelFileName is a str
        if not isinstance(modelFileName, str):  # modelFileName is a str
            raise TypeError("`modelFileName` expects type 'str', received '{}'".format(type(modelFileName).__name__))

        # ARG CHECK: modelFormat is an int
        if not isinstance(modelFormat, int):  # modelFormat is an int
            raise TypeError("`modelFormat` expects type 'int', received '{}'".format(type(modelFormat).__name__))

        # ARG CHECK: modelFormat is one of [1, 2, 3, 4]
        if isinstance(modelFormat, int):
            if modelFormat not in (1, 2, 3, 4):
                raise ValueError("`modelFormat` must be one of: 1, 2, 3, or 4 (preferred)")

        # try and call the function
        try:
            return super().saveVelocityModel(modelFileName, modelFormat)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setActiveNodeData(self, nodeId: int,
            depths: Tuple[float, ...], pvelocity: Tuple[float, ...],
            svelocity: Tuple[float, ...], gradient: Tuple[float, float]) -> None:
        """Modify the depth, velocity and gradient information associated with
        a specified active node in the `Grid`.

        Examples
        --------
            >>> slbm.setActiveNodeData(11, [-2.7, ..., 36.2], [1.5, ..., 8.1],
                                           [9e-5, ..., 4.5], [0.0017, 0.0017])

        Parameters
        -------
        nodeId : int
            Node number of the grid point in the model
        depths : tuple of floats
            Depths of the tops of the layers, in kilometers
        pvelocity : tuple of floats
            P velocities of all the intervals at the specified grid node, in
            kilometers per second
        svelocity : tuple of floats
            S velocities of all the intervals at the specified grid node, in
            kilometers per second
        gradient : tuple of floats
            P and S velocity gradients in the mantle, in 1/second

        Raises
        ------
        TypeError
            `nodeId` is not an int or remaining parameters are not lists/tuples
            of floats
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # nodeId is an int
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # ARG CHECK: all remaining parameters are lists or tuples
        if not all(isinstance(arg, (list, tuple)) for arg in (depths, pvelocity, svelocity, gradient)):
            raise TypeError("Parameters should be lists or tuples of floats")

        # ARG CHECK: all remaining parameters contain only floats
        if not all(isinstance(val, float) for val in depths):
            raise TypeError("Contents of `depths` should all be type 'float'")
        if not all(isinstance(val, float) for val in pvelocity):
            raise TypeError("Contents of `pvelocity` should all be type 'float'")
        if not all(isinstance(val, float) for val in svelocity):
            raise TypeError("Contents of `svelocity` should all be type 'float'")
        if not all(isinstance(val, float) for val in gradient):
            raise TypeError("Contents of `gradient` should all be type 'float'")

        # try and call the function
        try:
            return super().setActiveNodeData(nodeId, depths, pvelocity, svelocity, gradient)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setAverageMantleVelocity(self, waveType: int or str, velocity: float) -> None:
        """Set the average P or S wave mantle velocity.

        Examples
        --------
            >>> slbm.setAverageMantleVelocity('P', 8.1)

            >>> slbm.setAverageMantleVelocity(0, 8.1)

        Parameters
        ----------
        waveType : str or int
            Seismic wave type. Accepted values are
                * :attr:`~rstt.PWAVE`, `P`, or `0`
                * :attr:`~rstt.SWAVE`, `S`, or `1`
        velocity : float
            P or S wave velocity that is to be set, in kilometers per second

        Raises
        ------
        TypeError
            `waveType` isn't an `int` or a `str`
        ValueError
            An inappropriate `waveType` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: waveType is and int or str
        if not isinstance(waveType, (int, str)):  # waveType is an int or string
            raise TypeError("`waveType` expects type 'int' or 'str', received '{}'".format(type(waveType).__name__))

        # ARG CHECK: str waveType is one of [P, S]
        if isinstance(waveType, str):
            if waveType.lower() not in ('p', 's'):
                raise ValueError("`waveType` must be either 'P' or 'S'")

        # ARG CHECK: int waveType is one of [0, 1]
        if isinstance(waveType, int):
            if waveType not in (0, 1):
                raise ValueError("`waveType` must be 0 (P) or 1 (S)")

        # convert string waveType to int
        if isinstance(waveType, str):
            waveType = PWAVE if waveType.lower() == 'p' else SWAVE

        # try and call the function
        try:
            return super().setAverageMantleVelocity(waveType, velocity)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setCHMax(self, CH_MAX: float) -> None:
        """Set the current value of CH_MAX.

        This call sets the global parameter :attr:`~SlbmInterface.CH_MAX`.
        Alternatively, this parameter may be set by calling it as an attribute
        of the current :class:`SlbmInterface` object.

        `c` is the Zhao `c` parameter, and `h` is the turning depth of the ray
        below the Moho. The Zhao method only valid for `c*h << 1`. When `c*h >
        CH_MAX`, then RSTT will throw an exception.

        Examples
        --------
            >>> slbm.setCHMax(0.2)

            >>> slbm.CH_MAX = 0.2

        Parameters
        ----------
        CH_MAX : float
            Global :attr:`~SlbmInterface.CH_MAX` parameter

        Raises
        ------
        TypeError
            `CH_MAX` isn't a `float`
        ValueError
            An inappropriate `CH_MAX` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: CH_MAX is a float
        if not isinstance(CH_MAX, float):  # CH_MAX is a float
            raise TypeError("`CH_MAX` expects type 'float', received '{}'".format(type(CH_MAX).__name__))

        # ARG CHECK: CH_MAX > 0
        if not CH_MAX > 0:
            raise ValueError("`CH_MAX` must be greater than zero")

        # try and call the function
        try:
            return super().setCHMax(CH_MAX)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setDelDepth(self, delDepth: float) -> None:
        """Change the value of step change in depth used to compute depth
        derivatives.

        Examples
        --------
            >>> slbm.setDelDepth(0.1)

        Parameters
        ----------
        delDepth : float
            Step change in depth, in kilometers

        Raises
        ------
        TypeError
            `delDepth` isn't a `float`
        ValueError
            An inappropriate `delDepth` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: delDepth is a float
        if not isinstance(delDepth, float):  # delDepth is a float
            raise TypeError("`delDepth` expects type 'float', received '{}'".format(type(delDepth).__name__))

        # ARG CHECK: delDepth > 0
        if not delDepth > 0:
            raise ValueError("`delDepth` must be greater than zero")

        # try and call the function
        try:
            return super().setDelDepth(delDepth)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setDelDistance(self, delDistance: float) -> None:
        """Change the value of step change in distance used to compute
        horizontal derivatives.

        Examples
        --------
            >>> slbm.setDelDistance(0.1)

        Parameters
        ----------
        delDistance : float
            Step change in distance, in radians

        Raises
        ------
        TypeError
            `delDistance` isn't a `float`
        ValueError
            An inappropriate `delDistance` was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: delDistance is a float
        if not isinstance(delDistance, float):  # delDistance is a float
            raise TypeError("`delDepth` expects type 'float', received '{}'".format(type(delDistance).__name__))

        # ARG CHECK: delDistance > 0
        if not delDistance > 0:
            raise ValueError("`delDistance` must be greater than zero")

        # try and call the function
        try:
            return super().setDelDistance(delDistance)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setGridData(self, nodeId: int,
            depths: Tuple[float, ...], pvelocity: Tuple[float, ...],
            svelocity: Tuple[float, ...], gradient: Tuple[float, float]) -> None:
        """Modify the depth, velocity and gradient information associated with
        a specified node in the `Grid`.

        Examples
        --------
            >>> slbm.setGridData(11, [-2.7, ..., 36.2], [1.5, ..., 8.1],
                                     [9e-5, ..., 4.5], [0.0017, 0.0017])

        Parameters
        -------
        nodeId : int
            Node number of the grid point in the model
        depths : tuple of floats
            Depths of the tops of the layers, in kilometers
        pvelocity : tuple of floats
            P velocities of all the intervals at the specified grid node, in
            kilometers per second
        svelocity : tuple of floats
            S velocities of all the intervals at the specified grid node, in
            kilometers per second
        gradient : tuple of floats
            P and S velocity gradients in the mantle, in 1/second

        Raises
        ------
        TypeError
            `nodeId` is not an int or remaining parameters are not lists/tuples
            of floats
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: nodeId is an int
        if not isinstance(nodeId, int):  # nodeId is an int
            raise TypeError("`nodeId` expects type 'int', received '{}'".format(type(nodeId).__name__))

        # ARG CHECK: all remaining parameters are lists or tuples
        if not all(isinstance(arg, (list, tuple)) for arg in (depths, pvelocity, svelocity, gradient)):
            raise TypeError("Parameters should be lists or tuples of floats")

        # ARG CHECK: all remaining parameters contain only floats
        if not all(isinstance(val, float) for val in depths):
            raise TypeError("Contents of `depths` should all be type 'float'")
        if not all(isinstance(val, float) for val in pvelocity):
            raise TypeError("Contents of `pvelocity` should all be type 'float'")
        if not all(isinstance(val, float) for val in svelocity):
            raise TypeError("Contents of `svelocity` should all be type 'float'")
        if not all(isinstance(val, float) for val in gradient):
            raise TypeError("Contents of `gradient` should all be type 'float'")

        # try and call the function
        try:
            return super().setGridData(nodeId, depths, pvelocity, svelocity, gradient)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setInterpolatorType(self, interpolatorType: str) -> None:
        """Specify the interpolation type to use.

        With models loaded in the old RSTT formats 1 and 2, 'linear' is the only
        option allowed.

        Examples
        --------
            >>> slbm.setInterpolatorType('natural_neighbor')

        Parameters
        ----------
        interpolatorType : str
            Interpolation type, accepted values are:
                * linear
                * natural_neighbor

        Raises
        ------
        TypeError
            `interpolatorType` is not a str, or too many arguments were supplied
        ValueError
            An inappropriate `interpolatorType` value was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: interpolatorType is a str
        if not isinstance(interpolatorType, str):  # interpolatorType is a string
            raise TypeError("`interpolatorType` expects type 'str', received '{}'".format(type(interpolatorType).__name__))

        # ARG CHECK: str phase is one of ['linear', 'natural_neighbor']
        if interpolatorType.lower() not in ('linear', 'natural_neighbor'):
            raise ValueError("`interpolatorType` must be one of: 'linear', 'natural_neighbor'")

        # try and call the function
        try:
            return super().setInterpolatorType(interpolatorType)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setMaxDepth(self, maxDepth: float) -> None:
        """Set the maximum source depth for Pn/Sn phase.

        Examples
        --------
            >>> slbm.setMaxDepth(200.)

        Parameters
        -------
        maxDepth : float
            Maximum source depth for Pn/Sn phase, in kilometers

        Raises
        ------
        TypeError
            `maxDepth` is not a float, or too many arguments were supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: maxDepth is a float
        if not isinstance(maxDepth, float):  # maxDepth is a float
            raise TypeError("`maxDepth` expects type 'float', received '{}'".format(type(maxDepth).__name__))

        # try and call the function
        try:
            return super().setMaxDepth(maxDepth)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setMaxDistance(self, maxDistance: float) -> None:
        """Set the maximum source-receiver separation for Pn/Sn phase.

        Examples
        --------
            >>> slbm.setMaxDistance(0.261)

        Parameters
        -------
        maxDistance : float
            Maximum source-receiver separation for Pn/Sn phase, in radians

        Raises
        ------
        TypeError
            `maxDistance` is not a float, or too many arguments were supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: maxDistance is a float
        if not isinstance(maxDistance, float):  # maxDistance is a float
            raise TypeError("`maxDistance` expects type 'float', received '{}'".format(type(maxDistance).__name__))

        # try and call the function
        try:
            return super().setMaxDistance(maxDistance)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def setPathIncrement(self, pathIncrement: float) -> None:
        """Set the desired spacing of great circle nodes along the head wave
        interface.

        The actual spacing will be reduced from the requested value in order
        that an integral number of equally spaced `LayerProfile` objects will
        exactly span the source-receiver separation.

        Defaults to 0.1 degrees if not specified.

        Examples
        --------
            >>> slbm.setPathIncrement(0.00174)

        Parameters
        ----------
        pathIncrement : float
            Desired spacing of great circle nodes along the head wave interface,
            in radians

        Raises
        ------
        TypeError
            Provided path increment isn't `float`
        ValueError
            An inappropriate path increment was requested
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: pathIncrement is an float
        if not isinstance(pathIncrement, float):  # pathIncrement is an float
            raise TypeError("`pathIncrement` expects type 'float', received '{}'".format(type(pathIncrement).__name__))

        # ARG CHECK: pathIncrement >= 0
        if not pathIncrement >= 0:
            raise ValueError("`pathIncrement` must be greater than or equal to 0")

        # try and call the function
        try:
            return super().setPathIncrement(pathIncrement)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e


    def toString(self, verbosity: int = 999) -> str:
        """Returns a human-readable string representation of the `GreatCircle`

        Returns a human-readable string representation of the currently-instantiated
        `GreatCircle` object. The amount of information that is to be included
        in the return string is given by the `verbosity` parameter. Each
        `verbosity` level includes all information in preceeding levels.

            0. Nothing, an empty string is returned
            1. Total distance and travel time summary
            2. Gradient correction information for Pn/Sn, nothing for Pg/Lg
            3. Source and receiver `CrustalProfile` information
            4. `Grid` node weights
            5. Head wave interface profiles
            6. Interpolation coefficients for great circle nodes on the head
               wave interface
            7. Node hit count and node neighbors for every node touched by any
               `GreatCircle` instantiated by this instance of `SlbmInterface`

        Examples
        --------
            >>> slbm.toString()
            >>> slbm.toString(3)

        Parameters
        ----------
        verbosity : int
            Specifies the amount of information that is to be included in the
            return string. Each verbosity level includes all information in
            preceeding verbosity levels.

        Returns
        -------
        str
            Returns a human-readable string representation of the
            currently-instantiated `GreatCircle` object

        Raises
        ------
        TypeError
            `verbosity` is not an int, or too many arguments were supplied
        ValueError
            An inappropriate `verbosity` value was supplied
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # some error checking
        if not isinstance(verbosity, int):  # verbosity is an int
            raise TypeError("`verbosity` expects type 'int', received '{}'".format(type(verbosity).__name__))

        if verbosity < 0:
            raise ValueError("`verbosity expects a positive integer, received '{}'".format(verbosity))

        # try and call the function
        try:
            return super().toString(verbosity)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e

    def isEqual(self, other: object) -> bool:
        """Compares the model and/or great circle loaded into this and another
        SlbmInteface.

        This is functionally equivalent, and maps, to the overloaded == operator
        which tests whether the model and/or great circle loaded by the current
        instantiation of SlbmInterface is equal to that of another SlbmInterface.

        Examples
        --------
        >>> slbm1 = SlbmInterface()
        >>> slbm2 = SlbmInterface()
        >>> slbm1.loadVelocityModel("example.geotess")
        >>> slbm2.loadVelocityModel("example.geotess")
        >>> slbm1.isEqual(slbm2)
        True
        >>> slbm1.createGreatCircle("Pn", ...)
        >>> slbm2.createGreatCircle("Pg", ...)
        >>> slbm1.isEqual(slbm2)
        False

        Parameters
        ----------
        other : SlbmInterface
            The other SlbmInterface from which to compare its model and great
            circle.

        Returns
        -------
        bool
            Returns whether or not the model and (if applicable) great circle
            attached to the `other` SlbmInterface is equal to the existing one

        Raises
        ------
        TypeError
            Something other than an SlbmInterface was passed to `other`
        RuntimeError
            The RSTT C++ library raised an exception
        """

        # ARG CHECK: argument is another SlbmInterface
        if not isinstance(other, SlbmInterface):
            raise TypeError("`other` expects type 'SlbmInterface', received '{}'".format(type(other).__name__))

        # call operator ==
        return self == other


    # allow calling without instantiating a new SlbmInterface() via rstt.SlbmInterface.modelsEqual()
    @classmethod
    def modelsEqual(self, model_path1: str, model_path2: str) -> bool:
        """Check whether two models are equal

        Examples
        --------
            >>> slbm.modelsEqual("../models/example.geotess", "../models/example.geotess")
            True

            This is also a *classmethod* and can be used without instantiating a
            new SlbmInterface object.

            >>> rstt.SlbmInterface.modelsEqual("../models/example.geotess", "../models/example.geotess")
            True

        Parameters
        ----------
        model_path1 : str
            Path to RSTT model, e.g., `/path/to/modelfile.geotess`. Relative
            path names are accepted.
        model_path2 : str
            Path to RSTT model, e.g., `/path/to/modelfile.geotess`. Relative
            path names are accepted.

        Raises
        ------
        TypeError
            `model_path` is not a `str`, or too many arguments were supplied
        FileNotFoundError
            The specified `model_path` was not found 
        RuntimeError
            The RSTT C++ library raised an exception
        Exception
            An unknown exception occurred
        """

        # ARG CHECK: model_path is a str
        if not isinstance(model_path1, str) or not isinstance(model_path2, str):
            raise TypeError("`model_path` expects type 'str', received '{}'".format(type(model_path).__name__))

        # ARG CHECK: model_path exists
        if not os.path.exists(model_path1):
            raise FileNotFoundError("File does not exist: {}".format(model_path1))
        if not os.path.exists(model_path2):
            raise FileNotFoundError("File does not exist: {}".format(model_path2))

        # try and call the function
        try:
            return super().modelsEqual(model_path1, model_path2)

        # catch PyBind and unknown exceptions
        except (RuntimeError, Exception) as e:
            raise e
