
# Copyright (C) 2020 Michael Coughlin
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

"""Earthquake json file generator.

This script generates earthquake json files using notices from the
internet and USGS PDL client.

Comments should be e-mailed to michael.coughlin@ligo.org.

"""

import os, sys, glob, optparse, warnings, time, json

if not os.getenv("DISPLAY", None):
    import matplotlib
    matplotlib.use("agg", warn=False)

from datetime import datetime
import numpy as np
import subprocess
from subprocess import Popen
from lxml import etree

#import lal.gpstime
import astropy.time

from seismon import (eqmon, utils)

__author__ = "Michael Coughlin <michael.coughlin@ligo.org>"
__version__ = 1.0
__date__    = "9/22/2013"

# =============================================================================
#
#                               DEFINITIONS
#
# =============================================================================

def parse_commandline():
    """@parse the options given on the command-line.
    """
    parser = optparse.OptionParser(usage=__doc__,version=__version__)

    parser.add_option("-p", "--paramsFile", help="Seismon params file.",
                      default ="/home/mcoughlin/Seismon/seismon/input/seismon_params_traveltimes.txt")
    parser.add_option("-c", "--paramsFileCopy", help="Seismon copy params file.",
                      default ="/home/mcoughlin/Seismon/seismon/input/seismon_params_traveltimes_copy.txt")

    parser.add_option("-t", "--publicFileType", help="Type of public data.",
                      default ="hour")
    parser.add_option("-s", "--gpsStart", help="GPS Start Time.", default=1000000000,type=int)
    parser.add_option("-e", "--gpsEnd", help="GPS End Time.", default=1200000000,type=int)
    parser.add_option("-m", "--minMagnitude", help="Minimum earthquake magnitude.", default=5.0,type=float)
    parser.add_option("-v", "--verbose", action="store_true", default=False,
                      help="Run verbosely. (Default: False)")

    parser.add_option("--doPublic",  action="store_true", default=False)
    parser.add_option("--doPrivate",  action="store_true", default=False)
    parser.add_option("--doDatabase",  action="store_true", default=False)
    parser.add_option("--doIRIS",  action="store_true", default=False)
    parser.add_option("--doFake",  action="store_true", default=False)
    parser.add_option("--doMultipleEvents",  action="store_true", default=False)
    parser.add_option("--doCopy",  action="store_true", default=False)
    parser.add_option("--doPurge",  action="store_true", default=False)
    parser.add_option("--doMoment",  action="store_true", default=False)
    parser.add_option("--doCMT",  action="store_true", default=False)

    opts, args = parser.parse_args()

    # show parameters
    if opts.verbose:
        print >> sys.stderr, ""
        print >> sys.stderr, "running network_eqmon..."
        print >> sys.stderr, "version: %s"%__version__
        print >> sys.stderr, ""
        print >> sys.stderr, "***************** PARAMETERS ********************"
        for o in opts.__dict__.items():
          print >> sys.stderr, o[0]+":"
          print >> sys.stderr, o[1]
        print >> sys.stderr, ""

    return opts

def params_struct(opts):
    """@create params structure

    @param opts
        command line options
    """

    params = utils.readParamsFromFile(opts.paramsFile)
    params["publicFileType"] = opts.publicFileType
    params["gpsStart"] = opts.gpsStart
    params["gpsEnd"] = opts.gpsEnd
    params["minMagnitude"] = opts.minMagnitude

    params["doPublic"] = opts.doPublic
    params["doPrivate"] = opts.doPrivate
    params["doDatabase"] = opts.doDatabase
    params["doIRIS"] = opts.doIRIS
    params["doFake"] = opts.doFake
    params["doMultipleEvents"] = opts.doMultipleEvents
    params["doCopy"] = opts.doCopy
    params["doPurge"] = opts.doPurge
    params["doMoment"] = opts.doMoment
    params["doCMT"] = opts.doCMT

    params["paramsFile"] = opts.paramsFile
    params["paramsFileCopy"] = opts.paramsFileCopy

    return params

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)

def write_file(file,tree):
    """@write eqmon file

    @param file
        eqmon file
    @param tree
        xml tree
    """

    f = open(file,'w+')
    f.write('%s'%tree)
    f.close()

def write_info(file,attributeDic):
    """@write eqmon file

    @param file
        eqmon file
    @param attributeDic
        eqmon structure
    """

    root = etree.Element('eqmon')
    for key, value in attributeDic.items():
        if not key == "traveltimes":
            element = etree.SubElement(root,key)
            element.text = str(value)
    if "traveltimes" in attributeDic:
        element = etree.SubElement(root,'traveltimes')
        for key, value in attributeDic["traveltimes"].items():
            subelement = etree.SubElement(element,key)
            for category in value:
                if category in ["Latitudes","Longitudes","arrivalMin","arrivalMax"]:
                    continue
                subsubelement = etree.SubElement(subelement,category)
                subsubelement.text = write_array(value[category])

    tree = etree.tostring(root, pretty_print=True).decode()
    write_file(file,tree)
    #tree = etree.ElementTree(root)
    #tree.write(file, pretty_print=True, xml_declaration=True)

def write_array(array):
    """@write array

    @param array
        write array of value
    """
    if len(array) == 1:
        array = np.array(array).flatten()
        text = str(array[0])
    else:
        text = ' '.join([str(x) for x in array])
    return text

def write_context(path):
    """@write context file

    @param path
        path to earthquake directory
    """

    tm = time.struct_time(time.gmtime())
    dt = datetime.fromtimestamp(time.mktime(tm))
    currentGPS = astropy.time.Time(dt, format='datetime', scale='utc').gps

    files = glob.glob(os.path.join(path,"*.xml"))

    f = open(os.path.join(path,"context.txt"),"w")
    for file in files:
        fileSplit = file.split("/")
        fileName = fileSplit[-1]
        if fileName == "context.txt":
            continue

        fileNameSplit = fileName.replace(".xml","").split("-")
        fileGPS = int(fileNameSplit[-1])

        if fileGPS < currentGPS - 12*3600:
            continue

        f.write("%s\n"%fileName)
    f.close()

def delete_files(path,gps):
    """@delete eqmon files

    @param path
        path to eqmon files
    @param gps
        gps time before which to delete files
    """

    files = glob.glob(os.path.join(path,"*.xml"))

    for file in files:
        fileSplit = file.split("/")
        fileName = fileSplit[-1]
        if fileName == "context.txt":
            continue
        fileNameSplit = fileName.replace(".xml","").split("-")
        fileGPS = int(fileNameSplit[-1])
        
        if fileGPS < gps:
            os.system("rm %s"%file)

def readParamsFromFileCopy(file):
    """@read seismon params file

    @param file
        seismon params file
    """

    params = {}
    if os.path.isfile(file):
        with open(file,'r') as f:
            for line in f:
                line_without_return = line.split("\n")
                line_split = line_without_return[0].split(",")
                params[line_split[0]] = line_split[1].replace('"','')
    return params

def rsync_files(params):
    """@rsync eqmon files

    @param path
        path to rsync 
    """

    import pexpect

    paramsCopy = readParamsFromFileCopy(params["paramsFileCopy"])

    user = paramsCopy["user"]
    password = paramsCopy["password"]
    host = paramsCopy["host"]
    path = paramsCopy["path"]

    rsyncCommand = 'rsync -avz --delete %s %s:%s' % (params["eventfilesLocation"],host,path)
    child = pexpect.spawn(rsyncCommand)
    i = child.expect("id_rsa':",timeout=20)
    child.sendline(password)
    data = child.read()
    child.close()

def download_publiceventfiles(params):
    """@download events from usgs website

    @param params
        seismon params structure
    """

    path = params["publicdataLocation"]

    if params["publicFileType"] == "hour":
        file = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson"
    elif params["publicFileType"] == "month":
        file = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/4.5_month.geojson"
    elif params["publicFileType"] == "day":
        file = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson"
    else:
        error("Public file type not supported")

    x = subprocess.Popen(["wget",file,"-O","%s/events.txt"%path])
    x.wait()
    if x.returncode==0:
        print('Copying complete')
    else:
        print('Copying failed')

def save_fake_event(params,timeFolder,eventName):

    attributeDic = []
    eqmonfile = os.path.join(timeFolder,"eqmon.xml")
    quakemlfile = os.path.join(timeFolder,"quakeml.xml")

    #if os.path.isfile(os.path.join(timeFolder,"eqxml.txt")):
    #    return

    f = open(os.path.join(timeFolder,"eqxml.txt"),"w")
    f.write("Done")
    f.close()

    attributeDic = eqmon.read_eqmon([],eqmonfile)

    if attributeDic == []:
        return

    if (not "GPS" in attributeDic) or (not "Magnitude" in attributeDic):
        return

    if params["doMultipleEvents"]:
        file = os.path.join(params["eventfilesLocation"],"fake/%s-%.0f-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"],attributeDic["SentGPS"]))
    else:
        file = os.path.join(params["eventfilesLocation"],"fake/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))

    if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
        write_info(file,attributeDic)

        print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))

def save_moment_event(params,timeFolder,eventName):

    attributeDic = []
    productfile = os.path.join(timeFolder,"quakeml.xml")

    if os.path.isfile(os.path.join(timeFolder,"eqxml.txt")):
        return

    #f = open(os.path.join(timeFolder,"eqxml.txt"),"w")
    #f.write("Done")
    #f.close()

    if os.path.isfile(productfile):
        attributeDic = eqmon.read_product(productfile,eventName)

    if attributeDic == []:
        return

    if params["doMultipleEvents"]:
        file = os.path.join(params["eventfilesLocation"],"moment/%s-%.0f-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"],attributeDic["SentGPS"]))
    else:
        file = os.path.join(params["eventfilesLocation"],"moment/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))

    if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
        write_info(file,attributeDic)

        print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))

def save_private_event(params,timeFolder,eventName):

    attributeDic = []
    eqxmlfile = os.path.join(timeFolder,"eqxml.xml")
    quakemlfile = os.path.join(timeFolder,"quakeml.xml")

    #if os.path.isfile(os.path.join(timeFolder,"eqxml.txt")):
    #    return

    f = open(os.path.join(timeFolder,"eqxml.txt"),"w")
    f.write("Done")
    f.close()

    if os.path.isfile(eqxmlfile):
        attributeDic = eqmon.read_eqxml(eqxmlfile,eventName)
    elif os.path.isfile(quakemlfile):
        attributeDic = eqmon.read_quakeml(quakemlfile,eventName)

    if attributeDic == []:
        return

    if (not "GPS" in attributeDic) or (not "Magnitude" in attributeDic):
        return

    if params["doMultipleEvents"]:
        #filename = os.path.join(params["eventfilesLocation"],"private/%s-%.0f-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"],attributeDic["SentGPS"]))
        filename = os.path.join(params["eventfilesLocation"],"private/%s-%.0f-%.0f.json"%(attributeDic["eventName"],attributeDic["GPS"],attributeDic["SentGPS"]))
    else:
        #filename = os.path.join(params["eventfilesLocation"],"private/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))
        filename = os.path.join(params["eventfilesLocation"],"private/%s-%.0f.json"%(attributeDic["eventName"],attributeDic["GPS"]))

    if (attributeDic["GPS"] < params["gpsStart"]) or \
       (attributeDic["GPS"] > params["gpsEnd"]):
        return

    if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
        #write_info(filename, attributeDic)
        with open(filename, 'w') as json_file:
            json.dump(attributeDic, json_file, cls=NumpyEncoder)

        print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))

def cmt_events(params):
    """@write pdl events

    @param params
        seismon params structure
    """

    numEventsAdded = 0

    years = np.arange(2007,2018)
    years = np.arange(2017,2018)
    months = ["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]

    import obspy

    for year in years:
        for month in months:
            try:
                catfile = "http://www.ldeo.columbia.edu/~gcmt/projects/CMT/catalog/NEW_MONTHLY/%d/%s%d.ndk"%(year,month,np.mod(year,100))
                cat = obspy.readEvents(catfile)
                print(catfile)
            except:
                continue 

            for event in cat:
                attributeDic = eqmon.cmtread(event)

                print(attributeDic["GPS"], attributeDic["Magnitude"], attributeDic["Latitude"],attributeDic["Longitude"])

                if not "GPS" in attributeDic:
                    continue
                if os.path.isfile(os.path.join(params["eventfilesLocation"],"cmt/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))):
                    continue

                file = os.path.join(params["eventfilesLocation"],"cmt/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))
                if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
                    write_info(file,attributeDic)

                    print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))
                    numEventsAdded = numEventsAdded + 1

    return numEventsAdded

def moment_events(params):
    """@write pdl events

    @param params
        seismon params structure
    """

    numEventsAdded = 0

    folders = glob.glob(os.path.join(params["momentDataLocation"],"*"))
    #folders = []
    for numFolder in range(len(folders)):

        folder = folders[numFolder]

        folderSplit = folder.split("/")
        eventName = folderSplit[len(folderSplit) - 1]

        dataFolder = os.path.join(params["momentDataLocation"],eventName,eventName[0:2])
        timeFolders = glob.glob(os.path.join(dataFolder,"*"))
        timeFolders = sorted(timeFolders)

        if timeFolders == []:
            continue

        if params["doMultipleEvents"]:
            if len(timeFolders) == 1:
                continue

        for timeFolder in timeFolders:
                save_moment_event(params,timeFolder,eventName)
                numEventsAdded = numEventsAdded + 1

    return numEventsAdded

def private_events(params):
    """@write pdl events

    @param params
        seismon params structure
    """

    numEventsAdded = 0

    if params["doPurge"]:
        sys_command = "find %s/* -type d -mtime +7 -exec rm -rf {} \;"%params["dataLocation"]
        os.system(sys_command)
        sys_command = "find %s/* -type d -mtime +7 -exec rm -rf {} \;"%params["internalDataLocation"]
        os.system(sys_command)

    folders = glob.glob(os.path.join(params["dataLocation"],"*"))
    #folders = []
    for numFolder in range(len(folders)):

        folder = folders[numFolder]

        folderSplit = folder.split("/")
        eventName = folderSplit[len(folderSplit) - 1]
        dataFolder = os.path.join(params["dataLocation"],eventName,eventName[0:2])
        timeFolders = glob.glob(os.path.join(dataFolder,"*"))
        timeFolders = sorted(timeFolders)

        if timeFolders == []:
            continue

        if params["doMultipleEvents"]:
            if len(timeFolders) == 1:
                continue

        for timeFolder in timeFolders:
                save_private_event(params,timeFolder,eventName)
                numEventsAdded = numEventsAdded + 1

    folders = glob.glob(os.path.join(params["internalDataLocation"],"*"))
    for numFolder in range(len(folders)):

        folder = folders[numFolder]

        folderSplit = folder.split("/")
        eventName = folderSplit[len(folderSplit) - 1]
        dataFolder = os.path.join(params["internalDataLocation"],eventName,eventName[0:2])
        timeFolders = glob.glob(os.path.join(dataFolder,"*"))
        timeFolders = sorted(timeFolders)

        if timeFolders == []:
            continue

        if params["doMultipleEvents"]:
            if len(timeFolders) == 1:
                continue

        for timeFolder in timeFolders:
                save_private_event(params,timeFolder,eventName)
                numEventsAdded = numEventsAdded + 1

    path = os.path.join(params["eventfilesLocation"],"private")
    write_context(path)

    return numEventsAdded

def public_events(params):
    """@write usgs website events

    @param params
        seismon params structure
    """

    numEventsAdded = 0

    download_publiceventfiles(params)
    events_text = open(os.path.join(params["publicdataLocation"],"events.txt"),"r").read()
    events = json.loads(events_text)

    for event in events["features"]:
        attributeDic = eqmon.jsonread(event)

        if not "GPS" in attributeDic:
            continue
        if os.path.isfile(os.path.join(params["eventfilesLocation"],"public/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))):
            continue

        if (attributeDic["GPS"] < params["gpsStart"]) or \
           (attributeDic["GPS"] > params["gpsEnd"]):
            continue

        #filename = os.path.join(params["eventfilesLocation"],"public/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))
        filename = os.path.join(params["eventfilesLocation"],"public/%s-%.0f.json"%(attributeDic["eventName"],attributeDic["GPS"]))
        if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
            #write_info(filename,attributeDic)
            with open(filename, 'w') as json_file: 
                json.dump(attributeDic, json_file, cls=NumpyEncoder)

            print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))
            numEventsAdded = numEventsAdded + 1

    return numEventsAdded

def database_events(params):
    """@write usgs database events

    @param params
        seismon params structure
    """

    numEventsAdded = 0

    with open(os.path.join(params["databasedataLocation"],"events.txt")) as f:

        for line in f:

            event = line.replace("\n","")
            attributeDic = eqmon.databaseread(event)

            if not "GPS" in attributeDic:
                continue
            if os.path.isfile(os.path.join(params["eventfilesLocation"],"database/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))):
                continue

            file = os.path.join(params["eventfilesLocation"],"database/%s-%.0f.xml"%(attributeDic["eventName"],attributeDic["GPS"]))
            if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
                write_info(file,attributeDic)

            print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))
            numEventsAdded = numEventsAdded + 1

    return numEventsAdded

def iris_events(params):
    """@write usgs database events

    @param params
        seismon params structure
    """

    import obspy.clients.fdsn, obspy.core

    #starttime = lal.gpstime.gps_to_utc(params["gpsStart"])
    #endtime = lal.gpstime.gps_to_utc(params["gpsEnd"])
    #starttime = obspy.core.UTCDateTime(starttime)
    #endtime = obspy.core.UTCDateTime(endtime)

    starttime = astropy.time.Time(params["gpsStart"], format='gps')
    endtime = astropy.time.Time(params["gpsEnd"], format='gps')
    starttime = obspy.core.UTCDateTime(starttime.utc.iso)
    endtime = obspy.core.UTCDateTime(endtime.utc.iso)

    client = obspy.clients.fdsn.Client("IRIS")
    #client = obspy.fdsn.client.Client("http://earthquake.usgs.gov")
    
    events = client.get_events(minmagnitude=params["minMagnitude"],starttime=starttime,endtime=endtime)

    ifos = ["LHO","LLO","GEO","VIRGO","Homestake","FortyMeter","MIT"]

    numEventsAdded = 0
    for event in events.events:
        attributeDic = eqmon.irisread(event)

        print(attributeDic["GPS"], attributeDic["Magnitude"], attributeDic["Latitude"],attributeDic["Longitude"])

        for ifo in ifos:
            attributeDicTemp = eqmon.eqmon_loc(attributeDic,ifo)
            traveltimes = attributeDicTemp["traveltimes"][ifo]
            print("%s %.0f %.0f %.0f %.0f %.0f %.5e %.0f"%(ifo,max(traveltimes["Ptimes"]),max(traveltimes["Stimes"]),max(traveltimes["Rtwotimes"]),max(traveltimes["RthreePointFivetimes"]),max(traveltimes["Rfivetimes"]),traveltimes["Rfamp"][0],max(traveltimes["Distances"])))
        print("")
        print("")

        if not "GPS" in attributeDic:
            continue
        filename = os.path.join(params["eventfilesLocation"],"iris/%s-%.0f.json"%(attributeDic["eventName"],attributeDic["GPS"]))
        if os.path.isfile(filename):
            continue

        if (attributeDic["GPS"] < params["gpsStart"]) or \
           (attributeDic["GPS"] > params["gpsEnd"]):
            continue

        if attributeDic["Magnitude"] >= float(params["minMagnitude"]):
            #write_info(filename,attributeDic)
            with open(filename, 'w') as json_file:
                json.dump(attributeDic, json_file, cls=NumpyEncoder)

            print("%s added at "%attributeDic["eventName"], time.time(), ". %.3f seconds after event"%(attributeDic["SentGPS"] - attributeDic["GPS"]))
            numEventsAdded = numEventsAdded + 1

    return numEventsAdded

def fake_events(params):
    """@write fake events

    @param params
        seismon params structure
    """

    numEventsAdded = 0
    folders = glob.glob(os.path.join(params["eventfilesLocation"],"fakepdl/*"))
    #folders = []
    for numFolder in range(len(folders)):

        folder = folders[numFolder]

        folderSplit = folder.split("/")
        eventName = folderSplit[len(folderSplit) - 1]

        dataFolder = os.path.join(params["eventfilesLocation"],"fakepdl",eventName,eventName[0:2])
        timeFolders = glob.glob(os.path.join(dataFolder,"*"))
        timeFolders = sorted(timeFolders)

        if timeFolders == []:
            continue

        if params["doMultipleEvents"]:
            if len(timeFolders) == 1:
                continue

        for timeFolder in timeFolders:
                save_fake_event(params,timeFolder,eventName)
                numEventsAdded = numEventsAdded + 1
        
    return numEventsAdded


def run_traveltimes():
    """@run traveltime calculator
    """

    warnings.filterwarnings("ignore")

    # Parse command line
    opts = parse_commandline()
    # Parse command line
    params = params_struct(opts)

    if params["doPublic"]:
        print("Running public events...")
        numEventsAddedPublic = public_events(params)
    if params["doPrivate"]:
        print("Running private events...")
        numEventsAddedPrivate = private_events(params)
    if params["doDatabase"]:
        print("Running database events...")
        numEventsAddedDatabase = database_events(params)
    if params["doIRIS"]:
        print("Running IRIS events...")
        numEventsIRIS = iris_events(params)
    if params["doFake"]:
        print("Running Fake events...")
        numEventsFake = fake_events(params)
    if params["doCopy"]:
        print("Copying events...")
        rsync_files(params)
    if params["doMoment"]:
        print("Running moment tensor events...")
        numEventsAddedMoment = moment_events(params)
    if params["doCMT"]:
        print("Running CMT moment tensor events...")
        numEventsAddedCMT = cmt_events(params)

# =============================================================================
#
#                                    MAIN
#
# =============================================================================

if __name__=="__main__":

    run_traveltimes()

