Beispiel #1
0
def computeZoneFMD(cls, feature, catalog=None):
    """Compute FMD for selected feature."""

    if catalog is None:
        # cut catalog to feature
        polylist, vertices = utils.polygonsQGS2Shapely((feature, ))
        poly = polylist[0]

        # cut catalog with selected polygon
        catalog = QPCatalog.QPCatalog()
        catalog.merge(cls.catalog)
        catalog.cut(geometry=poly)

        # cut catalog with min/max depth according to UI spinboxes
        (mindepth, maxdepth) = eqcatalog.getMinMaxDepth(cls)
        catalog.cut(mindepth=mindepth, maxdepth=maxdepth)

    # Mc method
    if unicode(cls.comboBoxMcMethod.currentText()) == 'userDefined':
        mc = cls.spinboxFMDMcMethod.value()
    else:
        mc = unicode(cls.comboBoxMcMethod.currentText())

    return FMDMulti(catalog.eventParameters,
                    Mc=mc,
                    minEventsGR=MIN_EVENTS_FOR_GR,
                    time_span=cls.catalog_time_span[0])
def loadEQCatalogFromFile(catalog_path):
    """Load EQ catalog layer from ASCII catalog file, independent of 
    QGis UI.
    """

    catalog = QPCatalog.QPCatalog()

    if catalog_path.endswith('.gz'):
        catalog.importZMAP(catalog_path, minimumDataset=True, compression='gz')
    else:
        catalog.importZMAP(catalog_path, minimumDataset=True)

    # cut catalog to years > 1900 (because of datetime)
    # TODO(fab): change the datetime lib to mx.DateTime
    # catalog.cut(mintime='1900-01-01', mintime_exclude=True)

    # cut catalog below M=2.0 and remove potential NaN magnitudes
    catalog.cut(minmag=2.0, minmag_exclude=False, removeNaN=True)

    # PostGIS SRID 4326 is allocated for WGS84
    crs = QgsCoordinateReferenceSystem(
        4326, QgsCoordinateReferenceSystem.PostgisCrsId)

    # create layer
    layer = QgsVectorLayer("Point", "EQ catalog", "memory")
    layer.setCrs(crs)
    pr = layer.dataProvider()

    # add fields
    pr.addAttributes([
        QgsField("magnitude", QVariant.Double),
        QgsField("depth", QVariant.Double)
    ])

    # add EQs as features
    for curr_event in catalog.eventParameters.event:
        curr_ori = curr_event.getPreferredOrigin()

        # skip events without magnitude
        try:
            curr_mag = curr_event.getPreferredMagnitude()
        except IndexError:
            continue

        curr_lon = curr_ori.longitude.value
        curr_lat = curr_ori.latitude.value
        magnitude = curr_mag.mag.value

        try:
            depth = curr_ori.depth.value
        except AttributeError:
            depth = numpy.nan

        f = QgsFeature()
        f.setGeometry(QgsGeometry.fromPoint(QgsPoint(curr_lon, curr_lat)))
        f[0] = QVariant(magnitude)
        f[1] = QVariant(depth)
        pr.addFeatures([f])

    return (layer, catalog)
Beispiel #3
0
def task_3():
    print "----- running task 3"

    catalog = QPCatalog.QPCatalog()
    catalog.readXML(EQ_CATALOG_TASK_3, compression='gz')

    print "number of events: %s" % catalog.size()

    fmd = catalog.getFmd()

    print "b value: %(bValue)s\na value: %(aValue)s" % (fmd.GR)

    # NOTE: the file extension is appended automatically, depending on the 
    # backend
    fmd.plot(FMD_PLOT_FILE, fmdtype='cumulative', backend='PS')
Beispiel #4
0
def task_2():
    print "----- running task 2"

    catalog = QPCatalog.QPCatalog()
    catalog.importGSE2_0Bulletin(EQ_CATALOG_TASK_2, compression='gz')

    print "number of events: %s" % catalog.size()

    catalogCompact = QPCatalogCompact.QPCatalogCompact()
    catalogCompact.update(catalog)

    ## sort catalog by magnitude
    indices = catalogCompact.catalog[:, catalogCompact.map['mag']].argsort(axis=0)
    catalogCompact.catalog = catalogCompact.catalog[numpy.flipud(indices)]

    catalogCompact.exportZMAP(EQ_CATALOG_RESULT_TASK_2)
Beispiel #5
0
def task_1():
    print "----- running task 1"

    catalog = QPCatalog.QPCatalog()

    # http://magma.geonet.org.nz/services/quake/quakeml/1.0.1/query?startDate=2010-09-01&endDate=2010-09-05
    # catalog_url = EQ_CATALOG_TASK_1
    catalog_url = "%s?startDate=%s&endDate=%s" % (GEONET_CATALOG_URL,
       TASK_2_START_DATE, TASK_2_END_DATE)

    catalog.readXML(catalog_url)
    print "number of events before filtering: %s" % catalog.size()

    catalog.cut(polygon=FILTER_POLYGON_TASK_1)
    print "number of events after polygon filtering: %s" % catalog.size()

    catalog.cut(minmag=FILTER_MAGNITUDE_MIN_TASK_1,
        maxdepth=FILTER_DEPTH_MAX_TASK_1)

    print "number of events after mag/depth filtering: %s" % catalog.size()

    catalog.exportZMAP(EQ_CATALOG_RESULT_TASK_1)
Beispiel #6
0
def updateDataFault(cls,
                    feature,
                    m_threshold=recurrence.FAULT_BACKGROUND_MAG_THRESHOLD):
    """Update or compute moment rates for selected feature of fault source
    zone layer.

    Input:
        feature         QGis polygon feature from fault source layer

    Output:
        parameters      dict of computed parameters
    """

    provider = cls.fault_source_layer.dataProvider()
    provider_fault_back = cls.fault_background_layer.dataProvider()
    provider_back = cls.background_zone_layer.dataProvider()

    parameters = {}

    # zone ID and title
    (feature_id, feature_name) = utils.getFeatureAttributes(
        cls.fault_background_layer, feature,
        features.FAULT_BACKGROUND_ATTRIBUTES_ID)

    if feature_name.toString() != '':
        zone_name_str = feature_name.toString()
    else:
        zone_name_str = ""

    parameters['plot_title_recurrence'] = 'Zone %s, %s' % (
        feature_id.toString(), zone_name_str)

    # get Shapely polygon from feature geometry
    polylist, vertices = utils.polygonsQGS2Shapely((feature, ))
    fault_poly = polylist[0]

    # fault zone polygon area in square kilometres
    parameters['area_fault_sqkm'] = utils.polygonAreaFromWGS84(
        fault_poly) * 1.0e-6

    # get buffer zone around fault zone (convert buffer distance to degrees)
    (bz_poly, parameters['area_bz_sqkm']) = utils.computeBufferZone(
        fault_poly, momentrate.BUFFER_AROUND_FAULT_ZONE_KM)

    # find fault background zone in which centroid of fault zone lies
    # NOTE: this can yield a wrong background zone if the fault zone
    # is curved and at the edge of background zone.
    # TODO(fab): use GIS "within" function instead, but note that fault
    # zone can overlap several BG zones
    (fbz, fbz_poly, parameters['area_fbz_sqkm']) = utils.findBackgroundZone(
        fault_poly.centroid, provider_fault_back)

    recurrence_attributes = attributes.getAttributesFromRecurrence(
        provider, feature)

    if recurrence_attributes is not None:
        parameters.update(recurrence_attributes)
    else:
        return None

    # get mmax and mcdist for FBZ from background zone
    (mcdist_qv, mmax_qv) = areasource.getAttributesFromBackgroundZones(
        fbz_poly.centroid, provider_back, areasource.MCDIST_MMAX_ATTRIBUTES)

    mmax = float(mmax_qv.toDouble()[0])
    mcdist = str(mcdist_qv.toString())

    parameters['mmax'] = mmax

    ## moment rate from EQs

    # get quakes from catalog (cut with fault background polygon)
    # cut catalog with min/max depth according to UI spinboxes
    (mindepth, maxdepth) = eqcatalog.getMinMaxDepth(cls)

    fbz_cat = QPCatalog.QPCatalog()
    fbz_cat.merge(cls.catalog)
    fbz_cat.cut(geometry=fbz_poly)
    fbz_cat.cut(mindepth=mindepth, maxdepth=maxdepth)

    bz_cat = QPCatalog.QPCatalog()
    bz_cat.merge(cls.catalog)
    bz_cat.cut(geometry=bz_poly)
    bz_cat.cut(mindepth=mindepth, maxdepth=maxdepth)

    parameters['eq_count_fbz'] = fbz_cat.size()
    parameters['eq_count_bz'] = bz_cat.size()

    # sum up moment from quakes (converted from Mw with Kanamori eq.)
    # use quakes in buffer zone
    magnitudes = []
    for ev in bz_cat.eventParameters.event:
        mag = ev.getPreferredMagnitude()
        magnitudes.append(mag.mag.value)

    moment = numpy.array(momentrate.magnitude2moment(magnitudes))

    # scale moment: per year and area (in km^2)
    parameters['mr_eq'] = moment.sum() / (parameters['area_bz_sqkm'] *
                                          cls.catalog_time_span[0])

    ## moment rate from activity (RM)

    # moment rates from activity: use a and b values from buffer zone

    act_bz_arr_a = parameters['activity_bz_act_a'].strip().split()
    act_bz_arr_b = parameters['activity_bz_act_b'].strip().split()

    a_bz_arr = [float(x) for x in act_bz_arr_a]
    b_bz_arr = [float(x) for x in act_bz_arr_b]

    a_values = a_bz_arr
    momentrates_arr = numpy.array(
        momentrate.momentrateFromActivity(a_values, b_bz_arr,
                                          mmax)) / cls.catalog_time_span[0]

    parameters['mr_activity'] = momentrates_arr.tolist()

    # moment rates from activity: use a and b values from FBZ
    # (above threshold)

    act_fbz_at_arr_a = parameters['activity_fbz_at_act_a'].strip().split()
    act_fbz_at_arr_b = parameters['activity_fbz_at_act_b'].strip().split()

    a_fbz_at_arr = [float(x) for x in act_fbz_at_arr_a]
    b_fbz_at_arr = [float(x) for x in act_fbz_at_arr_b]

    a_values = a_fbz_at_arr
    momentrates_fbz_at_arr = numpy.array(
        momentrate.momentrateFromActivity(a_values, b_fbz_at_arr,
                                          mmax)) / cls.catalog_time_span[0]

    parameters['mr_activity_fbz_at'] = momentrates_fbz_at_arr.tolist()

    parameters['activity_m_threshold'] = m_threshold

    # FMD from quakes in FBZ
    cls.feature_data_fault_source['fmd'] = fmd.computeZoneFMD(
        cls, feature, fbz_cat)
    (parameters['ml_a'], parameters['ml_b'], parameters['ml_mc'],
     parameters['ml_magctr']) = fmd.getFMDValues(
         cls.feature_data_fault_source['fmd'])

    ## moment rate from slip rate

    # TODO(fab): check correct scaling of moment rate from slip rate
    (moment_rate_min, moment_rate_max) = \
        momentrate.momentrateFromSlipRate(parameters['sliprate_min'],
            parameters['sliprate_max'],
            parameters['area_fault_sqkm'] * 1.0e6)

    parameters['mr_slip'] = [moment_rate_min, moment_rate_max]

    return parameters
def computeActivityFromBackground(feature,
                                  layer_fault_background,
                                  layer_background,
                                  catalog,
                                  mmin=atticivy.ATTICIVY_MMIN,
                                  m_threshold=FAULT_BACKGROUND_MAG_THRESHOLD,
                                  mindepth=eqcatalog.CUT_DEPTH_MIN,
                                  maxdepth=eqcatalog.CUT_DEPTH_MAX,
                                  ui_mode=True):
    """Compute activity parameters a and b for (i) fault background zone, and 
    (ii) from buffer zone around fault zone.
    
    Input:
        feature                     fault source zone
        layer_fault_background
        layer_background
        catalog
        mmin
        
    Output:
        TODO(fab)
    """

    activity = {}

    provider_fault_back = layer_fault_background.dataProvider()
    provider_back = layer_background.dataProvider()

    # get Shapely polygon from fault zone feature geometry
    polylist, vertices = utils.polygonsQGS2Shapely((feature, ))

    try:
        fault_poly = polylist[0]
    except IndexError:
        error_msg = "Background activity: invalid FSZ geometry, id %s" % (
            feature.id())
        if ui_mode is True:
            QMessageBox.warning(None, "FSZ Warning", error_msg)
        else:
            print error_msg
        return None

    # get buffer zone around fault zone (convert buffer distance to degrees)
    (bz_poly,
     bz_area) = utils.computeBufferZone(fault_poly,
                                        momentrate.BUFFER_AROUND_FAULT_ZONE_KM)

    # find fault background zone in which centroid of fault zone lies
    # NOTE: this can yield a wrong background zone if the fault zone
    # is curved and at the edge of background zone.
    # TODO(fab): use GIS "within" function instead, but note that fault
    # zone can overlap several BG zones
    (fbz, fbz_poly, fbz_area) = utils.findBackgroundZone(fault_poly.centroid,
                                                         provider_fault_back,
                                                         ui_mode=ui_mode)

    if fbz is None:
        error_msg = "Recurrence: could not determine FBZ for zone %s" % (
            feature.id())
        if ui_mode is True:
            QMessageBox.warning(None, "Recurrence Warning", error_msg)
        else:
            print error_msg
        fbz_id = None
    else:
        attribute_map_fbz = utils.getAttributeIndex(
            provider_fault_back, (features.FAULT_BACKGROUND_ATTR_ID, ),
            create=False)

        # get fault background zone ID
        id_name = features.FAULT_BACKGROUND_ATTR_ID['name']
        fbz_id = int(fbz[attribute_map_fbz[id_name][0]].toDouble()[0])

    # get mmax and mcdist for FBZ from background zone
    (mcdist_qv, mmax_qv) = areasource.getAttributesFromBackgroundZones(
        fbz_poly.centroid,
        provider_back,
        areasource.MCDIST_MMAX_ATTRIBUTES,
        ui_mode=ui_mode)

    if mcdist_qv is None or mmax_qv is None:
        error_msg = "Recurrence: could not determine mcdist or mmax for "\
            "zone %s" % (feature.id())
        if ui_mode is True:
            QMessageBox.warning(None, "Recurrence Warning", error_msg)
        else:
            print error_msg
        return None
    else:
        mmax = float(mmax_qv.toDouble()[0])
        mcdist = str(mcdist_qv.toString())

    ## moment rate from activity (RM)

    # a and b value from FBZ

    # cut catalog with depth constraint
    cat_cut = QPCatalog.QPCatalog()
    cat_cut.merge(catalog)
    cat_cut.cut(mindepth=mindepth, maxdepth=maxdepth)

    activity_fbz = atticivy.computeActivityAtticIvy((fbz_poly, ), (mmax, ),
                                                    (mcdist, ),
                                                    cat_cut,
                                                    mmin=mmin,
                                                    ui_mode=ui_mode)
    activity['fbz'] = {
        'ID': fbz_id,
        'area': fbz_area,
        'activity': activity_fbz[0]
    }

    # get separate catalogs below and above magnitude threshold

    cat_below_threshold = QPCatalog.QPCatalog()
    cat_below_threshold.merge(cat_cut)
    cat_below_threshold.cut(maxmag=m_threshold, maxmag_excl=True)

    cat_above_threshold = QPCatalog.QPCatalog()
    cat_above_threshold.merge(cat_cut)
    cat_above_threshold.cut(minmag=m_threshold, maxmag_excl=False)

    activity_below_threshold = atticivy.computeActivityAtticIvy(
        (fbz_poly, ), (mmax, ), (mcdist, ),
        cat_below_threshold,
        mmin=mmin,
        ui_mode=ui_mode)
    activity['fbz_below'] = {
        'ID': fbz_id,
        'area': fbz_area,
        'activity': activity_below_threshold[0]
    }

    activity_above_threshold = atticivy.computeActivityAtticIvy(
        (fbz_poly, ), (mmax, ), (mcdist, ),
        cat_above_threshold,
        mmin=mmin,
        ui_mode=ui_mode)
    activity['fbz_above'] = {
        'ID': fbz_id,
        'area': fbz_area,
        'activity': activity_above_threshold[0]
    }

    # a and b value on buffer zone
    activity_bz = atticivy.computeActivityAtticIvy((bz_poly, ), (mmax, ),
                                                   (mcdist, ),
                                                   cat_cut,
                                                   mmin,
                                                   ui_mode=ui_mode)
    activity['bz'] = {'area': bz_area, 'activity': activity_bz[0]}

    activity['background'] = {'mmax': mmax, 'mcdist': mcdist}

    return activity
def computeActivityAtticIvy(polygons, mmax, mcdist, catalog, 
    mmin=ATTICIVY_MMIN, mindepth=eqcatalog.CUT_DEPTH_MIN,
    maxdepth=eqcatalog.CUT_DEPTH_MAX, ui_mode=True):
    """Computes a-and b values using Roger Musson's AtticIvy code for
    a set of source zone polygons.
    
    Input: 
        polygons        list of Shapely polygons for input zones
        mmax            list of mmax values
        mcdist          list of mcdist strings
        catalog         earthquake catalog as QuakePy object
        mmin            minimum magnitude used for AtticIvy computation

    Output: 
        list of (a, b, act_w, act_a, act_b) triples
    """
    
    if ui_mode is False:
        print "\n=== Running AtticIvy for %s features ===" % len(polygons)
            
    # create temp dir for computation
    temp_dir_base = os.path.dirname(__file__)
    temp_dir = tempfile.mkdtemp(dir=temp_dir_base)

    # NOTE: cannot use full file names, since they can be only 30 chars long
    # write zone data to temp file in AtticIvy format
    zone_file_path = os.path.join(temp_dir, ATTICIVY_ZONE_FILE)
    
    # return value is list of all internal zone IDs 
    zone_ids = writeZones2AtticIvy(zone_file_path, polygons, mmax, mcdist, 
        mmin, ui_mode=ui_mode)

    # do depth filtering on catalog
    # don't exclude events with 'NaN' values
    cat_cut = QPCatalog.QPCatalog()
    cat_cut.merge(catalog)
    cat_cut.cut(mindepth=mindepth, maxdepth=maxdepth)
    
    # write catalog to temp file in AtticIvy format
    catalog_file_path = os.path.join(temp_dir, ATTICIVY_CATALOG_FILE)
    cat_cut.exportAtticIvy(catalog_file_path)

    # start AtticIvy computation (subprocess)
    exec_file = os.path.basename(ATTICIVY_EXECUTABLE)

    # copy executable to temp dir
    shutil.copy(ATTICIVY_EXECUTABLE, temp_dir)

    retcode = subprocess.call(["./%s" % exec_file, ATTICIVY_ZONE_FILE, 
        ATTICIVY_CATALOG_FILE, str(ATTICIVY_BOOTSTRAP_ITERATIONS)], 
        cwd=temp_dir)
    
    if retcode != 0:
        error_msg = "AtticIvy Error. Return value: %s" % retcode
        if ui_mode is True:
            QMessageBox.warning(None, "AtticIvy Error", error_msg)
        else:
            print error_msg
            
    # read results from AtticIvy output file
    result_file_path = os.path.join(temp_dir, ATTICIVY_RESULT_FILE)
    activity_result = activityFromAtticIvy(result_file_path)
    
    # expand activity_result to original length with inserted None values
    # for zones that do not have valid data
    activity_list = []
    for curr_zone_id in zone_ids:
        if curr_zone_id in activity_result:
            zone_result = activity_result[curr_zone_id]
        else:
            zone_result = None
        
        activity_list.append(zone_result)

    # remove temp file directory
    shutil.rmtree(temp_dir)

    return activity_list
Beispiel #9
0
def updateDataFaultBackgr(cls,
                          feature,
                          m_threshold=recurrence.FAULT_BACKGROUND_MAG_THRESHOLD
                          ):
    """Update or compute moment rates for selected feature of fault background
    zone layer.

    Input:
        feature         QGis polygon feature from fault background zone layer

    Output:
        parameters      dict of computed parameters
    """

    provider = cls.fault_background_layer.dataProvider()
    provider_fault = cls.fault_source_layer.dataProvider()
    provider_area = cls.area_source_layer.dataProvider()
    provider_back = cls.background_zone_layer.dataProvider()

    parameters = {}

    # get Shapely polygon from feature geometry
    polylist, vertices = utils.polygonsQGS2Shapely((feature, ))
    poly = polylist[0]

    # get polygon area in square kilometres
    parameters['area_background_sqkm'] = \
        utils.polygonAreaFromWGS84(poly) * 1.0e-6

    # get mmax and mcdist for FBZ from background zone
    (mcdist_qv, mmax_qv) = areasource.getAttributesFromBackgroundZones(
        poly.centroid, provider_back, areasource.MCDIST_MMAX_ATTRIBUTES)

    mmax = float(mmax_qv.toDouble()[0])
    mcdist = str(mcdist_qv.toString())

    parameters['mmax'] = mmax

    ## moment rate from EQs

    # get quakes from catalog (cut with fault background zone polygon)
    poly_cat = QPCatalog.QPCatalog()
    poly_cat.merge(cls.catalog)
    poly_cat.cut(geometry=poly)

    # cut catalog with min/max depth according to UI spinboxes
    (mindepth, maxdepth) = eqcatalog.getMinMaxDepth(cls)
    poly_cat.cut(mindepth=mindepth, maxdepth=maxdepth)

    parameters['eq_count'] = poly_cat.size()

    # sum up moment from quakes (converted from Mw with Kanamori eq.)
    magnitudes = []
    for ev in poly_cat.eventParameters.event:
        mag = ev.getPreferredMagnitude()
        magnitudes.append(mag.mag.value)

    moment = numpy.array(momentrate.magnitude2moment(magnitudes))

    # scale moment: per year and area (in km^2)
    parameters['mr_eq'] = moment.sum() / (parameters['area_background_sqkm'] *
                                          cls.catalog_time_span[0])

    ## moment rate from activity (RM)

    parameters['activity_mmin'] = atticivy.ATTICIVY_MMIN
    activity = atticivy.computeActivityAtticIvy(
        (poly, ), (mmax, ), (mcdist, ),
        cls.catalog,
        mmin=parameters['activity_mmin'])

    # get RM (a, b) values from feature attribute
    activity_str_a = activity[0][3]
    activity_arr_a = activity_str_a.strip().split()
    activity_str_b = activity[0][4]
    activity_arr_b = activity_str_b.strip().split()

    # ignore weights
    activity_a = [float(x) for x in activity_arr_a]
    activity_b = [float(x) for x in activity_arr_b]
    parameters['activity_a'] = activity_a
    parameters['activity_b'] = activity_b

    a_values = activity_a
    momentrates_arr = numpy.array(
        momentrate.momentrateFromActivity(a_values, activity_b,
                                          mmax)) / cls.catalog_time_span[0]
    parameters['mr_activity'] = momentrates_arr.tolist()

    # get separate catalogs below and above magnitude threshold
    cat_below_threshold = QPCatalog.QPCatalog()
    cat_below_threshold.merge(poly_cat)
    cat_below_threshold.cut(maxmag=m_threshold, maxmag_excl=True)
    parameters['eq_count_below'] = cat_below_threshold.size()

    cat_above_threshold = QPCatalog.QPCatalog()
    cat_above_threshold.merge(poly_cat)
    cat_above_threshold.cut(minmag=m_threshold, maxmag_excl=False)
    parameters['eq_count_above'] = cat_above_threshold.size()

    activity_below_threshold = atticivy.computeActivityAtticIvy(
        (poly, ), (mmax, ), (mcdist, ),
        cat_below_threshold,
        mmin=parameters['activity_mmin'])

    activity_above_threshold = atticivy.computeActivityAtticIvy(
        (poly, ), (mmax, ), (mcdist, ),
        cat_above_threshold,
        mmin=parameters['activity_mmin'])

    # get RM (weight, a, b) values from feature attribute
    activity_below_str_a = activity_below_threshold[0][3]
    activity_below_arr_a = activity_below_str_a.strip().split()
    activity_below_str_b = activity_below_threshold[0][4]
    activity_below_arr_b = activity_below_str_b.strip().split()

    activity_above_str_a = activity_above_threshold[0][3]
    activity_above_arr_a = activity_above_str_a.strip().split()
    activity_above_str_b = activity_above_threshold[0][4]
    activity_above_arr_b = activity_above_str_b.strip().split()

    # ignore weights
    activity_below_a = [float(x) for x in activity_below_arr_a]
    activity_below_b = [float(x) for x in activity_below_arr_b]

    activity_above_a = [float(x) for x in activity_above_arr_a]
    activity_above_b = [float(x) for x in activity_above_arr_b]

    a_values_below = activity_below_a
    momentrates_below_arr = numpy.array(
        momentrate.momentrateFromActivity(a_values_below, activity_below_b,
                                          mmax)) / cls.catalog_time_span[0]

    a_values_above = activity_above_a
    momentrates_above_arr = numpy.array(
        momentrate.momentrateFromActivity(a_values_above, activity_above_b,
                                          mmax)) / cls.catalog_time_span[0]

    parameters['activity_below_a'] = activity_below_a
    parameters['activity_below_b'] = activity_below_b

    parameters['activity_above_a'] = activity_above_a
    parameters['activity_above_b'] = activity_above_b

    parameters['mr_activity_below'] = momentrates_below_arr.tolist()
    parameters['mr_activity_above'] = momentrates_above_arr.tolist()

    parameters['activity_m_threshold'] = m_threshold

    # FMD from quakes in FBZ
    cls.feature_data_fault_background['fmd'] = fmd.computeZoneFMD(
        cls, feature, poly_cat)
    (parameters['ml_a'], parameters['ml_b'], parameters['ml_mc'],
     parameters['ml_magctr']) = fmd.getFMDValues(
         cls.feature_data_fault_background['fmd'])

    ## moment rate from slip rate

    sliprate_min_name = features.FAULT_SOURCE_ATTR_SLIPRATE_MIN['name']
    sliprate_max_name = features.FAULT_SOURCE_ATTR_SLIPRATE_MAX['name']

    attribute_map = utils.getAttributeIndex(
        provider_fault, (features.FAULT_SOURCE_ATTR_SLIPRATE_MIN,
                         features.FAULT_SOURCE_ATTR_SLIPRATE_MAX),
        create=False)

    moment_rate_min = 0.0
    moment_rate_max = 0.0
    parameters['area_fault_sqkm'] = 0.0
    parameters['fault_count'] = 0

    provider_fault.rewind()
    for fault in provider_fault:

        fault_poly, vertices = utils.polygonsQGS2Shapely((fault, ))
        if fault_poly[0].intersects(poly):

            parameters['fault_count'] += 1

            sliprate_min = \
                fault[attribute_map[sliprate_min_name][0]].toDouble()[0]
            sliprate_max = \
                fault[attribute_map[sliprate_max_name][0]].toDouble()[0]
            area_fault = utils.polygonAreaFromWGS84(fault_poly[0])

            # TODO(fab): correct scaling of moment rate from slip rate
            (rate_min, rate_max) = momentrate.momentrateFromSlipRate(
                sliprate_min, sliprate_max, area_fault)

            moment_rate_min += rate_min
            moment_rate_max += rate_max
            parameters['area_fault_sqkm'] += area_fault

    moment_rate_min /= cls.catalog_time_span[0]
    moment_rate_max /= cls.catalog_time_span[0]

    parameters['mr_slip'] = [moment_rate_min, moment_rate_max]
    parameters['area_fault_sqkm'] *= 1.0e-6

    ## moment rate from geodesy (strain)

    momentrate_strain_barba = momentrate.momentrateFromStrainRateBarba(
        poly, cls.data.strain_rate_barba, cls.data.deformation_regimes_bird)
    parameters['mr_strain_barba'] = momentrate_strain_barba / (
        cls.catalog_time_span[0])

    momentrate_strain_bird = momentrate.momentrateFromStrainRateBird(
        poly, cls.data.strain_rate_bird, cls.data.deformation_regimes_bird)
    parameters['mr_strain_bird'] = momentrate_strain_bird / (
        cls.catalog_time_span[0])

    return parameters
Beispiel #10
0
def updateDataArea(cls, feature):
    """Update or compute moment rates for selected feature of area source
    zone layer.

    Input:
        feature         QGis polygon feature from area source layer

    Output:
        parameters      dict of computed parameters
    """

    provider = cls.area_source_layer.dataProvider()
    parameters = {}

    # get Shapely polygon from feature geometry
    polylist, vertices = utils.polygonsQGS2Shapely((feature, ))
    poly = polylist[0]

    # get polygon area in square kilometres
    parameters['area_sqkm'] = utils.polygonAreaFromWGS84(poly) * 1.0e-6

    # zone ID and title
    (feature_id, feature_title, feature_name) = utils.getFeatureAttributes(
        cls.area_source_layer, feature, features.AREA_SOURCE_ATTRIBUTES_ID)

    if feature_title.toString() == '' and feature_name.toString() == '':
        zone_name_str = ""
    elif feature_title.toString() == '' and feature_name.toString() != '':
        zone_name_str = feature_name.toString()
    elif feature_title.toString() != '' and feature_name.toString() == '':
        zone_name_str = feature_title.toString()
    else:
        zone_name_str = "%s, %s" % (feature_title.toString(),
                                    feature_name.toString())

    parameters['plot_title_fmd'] = 'Zone %s, %s' % (feature_id.toInt()[0],
                                                    zone_name_str)

    ## moment rate from EQs

    # get quakes from catalog (cut with polygon)
    poly_cat = QPCatalog.QPCatalog()
    poly_cat.merge(cls.catalog)
    poly_cat.cut(geometry=poly)

    # cut catalog with min/max depth according to UI spinboxes
    (mindepth, maxdepth) = eqcatalog.getMinMaxDepth(cls)
    poly_cat.cut(mindepth=mindepth, maxdepth=maxdepth)

    parameters['eq_count'] = poly_cat.size()

    # sum up moment from quakes (converted from Mw with Kanamori eq.)
    magnitudes = []
    for ev in poly_cat.eventParameters.event:
        mag = ev.getPreferredMagnitude()
        magnitudes.append(mag.mag.value)

    moment = numpy.array(momentrate.magnitude2moment(magnitudes))

    # scale moment: per year and area (in km^2)
    parameters['mr_eq'] = moment.sum() / (parameters['area_sqkm'] *
                                          cls.catalog_time_span[0])

    ## moment rate from activity (RM)

    # get attribute index of AtticIvy result
    attribute_map = utils.getAttributeIndex(
        provider,
        (features.AREA_SOURCE_ATTR_ACT_RM_A,
         features.AREA_SOURCE_ATTR_ACT_RM_B, features.AREA_SOURCE_ATTR_MMAX))

    attribute_act_a_name = features.AREA_SOURCE_ATTR_ACT_RM_A['name']
    attribute_act_a_idx = attribute_map[attribute_act_a_name][0]

    attribute_act_b_name = features.AREA_SOURCE_ATTR_ACT_RM_B['name']
    attribute_act_b_idx = attribute_map[attribute_act_b_name][0]

    attribute_mmax_name = features.AREA_SOURCE_ATTR_MMAX['name']
    attribute_mmax_idx = attribute_map[attribute_mmax_name][0]

    # get RM (a, b) values from feature attributes
    try:
        activity_a_str = str(feature[attribute_act_a_idx].toString())
        activity_a_arr = activity_a_str.strip().split()
    except KeyError:
        activity_a_arr = 3 * [numpy.nan]
        error_msg = "Moment balancing: no valid activity a parameter in %s" % (
            parameters['plot_title_fmd'])
        QMessageBox.warning(None, "Moment balancing warning", error_msg)

    try:
        activity_b_str = str(feature[attribute_act_b_idx].toString())
        activity_b_arr = activity_b_str.strip().split()
    except KeyError:
        activity_b_arr = 3 * [numpy.nan]
        error_msg = "Moment balancing: no valid activity b parameter in %s" % (
            parameters['plot_title_fmd'])
        QMessageBox.warning(None, "Moment balancing warning", error_msg)

    # ignore weights
    parameters['activity_mmin'] = atticivy.ATTICIVY_MMIN
    activity_a = [float(x) for x in activity_a_arr]
    activity_b = [float(x) for x in activity_b_arr]
    mmax = float(feature[attribute_mmax_idx].toDouble()[0])

    parameters['activity_a'] = activity_a
    parameters['activity_b'] = activity_b
    parameters['mmax'] = mmax

    ## Maximum likelihood a/b values
    if poly_cat.size() == 0:
        cls.feature_data_area_source['fmd'] = None
        (parameters['ml_a'], parameters['ml_b'], parameters['ml_mc'],
         parameters['ml_magctr']) = 4 * [numpy.nan]
        error_msg = "Moment balancing: no EQs in %s" % (
            parameters['plot_title_fmd'])
        QMessageBox.warning(None, "Moment balancing warning", error_msg)
    else:
        cls.feature_data_area_source['fmd'] = fmd.computeZoneFMD(
            cls, feature, poly_cat)
        (parameters['ml_a'], parameters['ml_b'], parameters['ml_mc'],
         parameters['ml_magctr']) = fmd.getFMDValues(
             cls.feature_data_area_source['fmd'])

    ## moment rate from activity
    a_values = activity_a
    momentrates_arr = numpy.array(
        momentrate.momentrateFromActivity(a_values, activity_b,
                                          mmax)) / cls.catalog_time_span[0]
    parameters['mr_activity'] = momentrates_arr.tolist()

    ## moment rate from geodesy (strain)
    momentrate_strain_barba = momentrate.momentrateFromStrainRateBarba(
        poly, cls.data.strain_rate_barba, cls.data.deformation_regimes_bird)
    parameters['mr_strain_barba'] = momentrate_strain_barba / (
        cls.catalog_time_span[0])

    momentrate_strain_bird = momentrate.momentrateFromStrainRateBird(
        poly, cls.data.strain_rate_bird, cls.data.deformation_regimes_bird)
    parameters['mr_strain_bird'] = momentrate_strain_bird / (
        cls.catalog_time_span[0])

    return parameters