예제 #1
0
DataModel::Origin* relocate(Seismology::LocatorInterface *locator, DataModel::Origin* origin) {
	if ( !locator )
		throw Core::GeneralException("No locator type set.");

	DataModel::Origin* newOrg = NULL;
	std::string errorMsg;

	try {
		newOrg = locator->relocate(origin);
		if ( newOrg )
			return newOrg;

		errorMsg = "The Relocation failed for some reason.";
	}
	catch ( Core::GeneralException& e ) {
		errorMsg = e.what();
	}

	// if no initial location is supported throw the error
	// after the first try
	if ( !locator->supports(Seismology::LocatorInterface::InitialLocation) )
		throw Core::GeneralException(errorMsg);

	Seismology::LocatorInterface::PickList picks;
	for ( size_t i = 0; i < origin->arrivalCount(); ++i ) {
		DataModel::Arrival* arrival = origin->arrival(i);
		try {
			if ( arrival->weight() < 0.5 ) continue;
		}
		catch ( ... ) {}

		DataModel::Pick* pick = locator->getPick(arrival);
		if ( !pick )
			throw Core::GeneralException("pick '" + arrival->pickID() + "' not found");

		picks.push_back(Seismology::LocatorInterface::WeightedPick(pick,1));
	}

	if ( picks.empty() )
		throw Core::GeneralException("No picks given to relocate");

	std::sort(picks.begin(), picks.end(), comparePick());
	DataModel::SensorLocation *sloc = locator->getSensorLocation(picks.front().first.get());
	if ( !sloc )
		throw Core::GeneralException("station '" + picks.front().first->waveformID().networkCode() +
		                             "." + picks.front().first->waveformID().stationCode() + "' not found");

	DataModel::OriginPtr tmp = DataModel::Origin::Create();
	*tmp = *origin;
	for ( size_t i = 0; i < origin->arrivalCount(); ++i ) {
		DataModel::ArrivalPtr ar = new DataModel::Arrival(*origin->arrival(i));
		tmp->add(ar.get());
	}

	tmp->setLatitude(sloc->latitude());
	tmp->setLongitude(sloc->longitude());
	tmp->setDepth(DataModel::RealQuantity(11.0));
	tmp->setTime(picks.front().first->time());

	newOrg = locator->relocate(tmp.get());

	if ( newOrg )
		return newOrg;

	throw Core::GeneralException(errorMsg);
}
예제 #2
0
/*!
 \brief Process one event

 This is called by processEvents() when iterating over all events in the cache
 */
void VsMagnitude::process(VsEvent *evt, Event *event) {
    if ( evt->stations.empty() )
        return;
    Client::Inventory *inv = Client::Inventory::Instance();

    double stmag;
    double distdg, epicdist, azi1, azi2;
    WaveformStreamID wid;
    ReturnCode ret;
    Timeline::StationList unused;
    evt->allThresholdStationsCount = 0;
    vs.seteqlat(evt->lat);
    vs.seteqlon(evt->lon);

    vector<VsInput> inputs;

    SEISCOMP_LOG(_processingInfoChannel,
                 "Start logging for event: %s", event->publicID().c_str());
    SEISCOMP_LOG(_processingInfoChannel, "update number: %d", evt->update);

    OriginPtr org = _cache.get<Origin>(event->preferredOriginID());
    if ( !org ) {
        SEISCOMP_WARNING("Object %s not found in cache\nIs the cache size big enough?\n"
                         "Have you subscribed to all necessary message groups?",
                         event->preferredOriginID().c_str());
        return;
    }

    evt->staMags.clear();
    VsWindows::iterator it;
    for ( it = evt->stations.begin(); it != evt->stations.end(); ++it ) {
        Envelope venv, henv;
        Core::Time vtime, htime;
        string locationCode, channelCode;


        ret = _timeline.maxmimum(it->first, it->second.startTime(),
                                 it->second.endTime(), it->second.pickTime(), venv, vtime, henv,
                                 htime, locationCode, channelCode);

        if ( no_data == ret ) {
            SEISCOMP_WARNING("No data available for %s.%s.%s", it->first.first.c_str(),
                             it->first.second.c_str(),locationCode.c_str());
            unused.insert(it->first);
            continue;
        }

        DataModel::SensorLocation *loc;
        loc = inv->getSensorLocation(it->first.first, it->first.second,
                                     locationCode, it->second.pickTime());
        if ( loc == NULL ) {
            SEISCOMP_WARNING(
                "%s.%s.%s: sensor location not in inventory: ignoring", it->first.first.c_str(), it->first.second.c_str(), locationCode.c_str());
            continue;
        }

        Math::Geo::delazi(evt->lat, evt->lon, loc->latitude(), loc->longitude(),
                          &distdg, &azi1, &azi2);
        epicdist = Math::Geo::deg2km(distdg);

        // if data is clipped or not enough to use it for magnitude
        // computation add the station to the overall count and then continue
        if ( not_enough_data == ret || clipped_data == ret) {
            SEISCOMP_WARNING("Not enough data available for %s.%s.%s", it->first.first.c_str(),
                             it->first.second.c_str(),locationCode.c_str());
            unused.insert(it->first);
            continue;
        }

        // catch remaining errors
        if ( index_error == ret || undefined_problem == ret)
            continue;

        if ( _maxepicdist > 0 ) {
            if( epicdist > _maxepicdist )
                continue;
        }

        inputs.resize(inputs.size() + 1);
        VsInput &input = inputs.back();
        input.lat = (float) loc->latitude();
        input.lon = (float) loc->longitude();

        SoilClass soilClass;
        float ca = siteEffect(input.lat, input.lon,
                              std::max(venv.values[Acceleration], henv.values[Acceleration]),
                              Acceleration, soilClass);
        float cv = siteEffect(input.lat, input.lon,
                              std::max(venv.values[Velocity], henv.values[Velocity]),
                              Velocity, soilClass);
        float cd = siteEffect(input.lat, input.lon,
                              std::max(venv.values[Displacement], henv.values[Displacement]),
                              Displacement, soilClass);

        // Convert from m to cm and apply site effect correction
        input.ZA = (float) (venv.values[Acceleration] / ca) * 100;
        input.ZV = (float) (venv.values[Velocity] / cv) * 100;
        input.ZD = (float) (venv.values[Displacement] / cd) * 100;

        input.HA = (float) (henv.values[Acceleration] / ca) * 100;
        input.HV = (float) (henv.values[Velocity] / cv) * 100;
        input.HD = (float) (henv.values[Displacement] / cd) * 100;

        input.PSclass =
            vs.psclass(input.ZA, input.ZV, input.HA, input.HV) == 0 ?
            P_Wave : S_Wave;
        input.SOILclass = soilClass;

        input.mest = vs.mest(vs.ground_motion_ratio(input.ZA, input.ZD),
                             input.PSclass);

        // Record single station magnitudes
        Notifier::SetEnabled(true);
        _creationInfo.setCreationTime(_currentTime);
        _creationInfo.setModificationTime(Core::None);
        DataModel::StationMagnitudePtr staMag = DataModel::StationMagnitude::Create();
        staMag->setMagnitude(RealQuantity(input.mest));
        staMag->setType("MVS");
        staMag->setCreationInfo(_creationInfo);
        wid.setNetworkCode(it->first.first);
        wid.setStationCode(it->first.second);
        wid.setLocationCode(locationCode);
        wid.setChannelCode(channelCode);
        staMag->setWaveformID(wid);
        org->add(staMag.get());
        evt->staMags.push_back(staMag);
        Notifier::SetEnabled(false);

        // Logging
        string resultstr;
        ostringstream out;
        out.precision(2);
        out.setf(ios::fixed, ios::floatfield);
        out << "Sensor: " << it->first.first << "." << locationCode << ".";
        out << it->first.second << "." << channelCode << "; ";
        out << "Wavetype: " << std::string(input.PSclass.toString()) << "; ";
        out << "Soil class: " << std::string(input.SOILclass.toString())
            << "; ";
        out << "Magnitude: " << input.mest;
        resultstr = out.str();
        out.str("");
        SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());
        out.precision(2);
        out.setf(ios::fixed, ios::floatfield);
        out << "station lat: " << input.lat << "; station lon: " << input.lon;
        out << "; epicentral distance: " << epicdist << ";";
        resultstr = out.str();
        out.str("");
        SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());
        out.precision(2);
        out.setf(ios::scientific, ios::floatfield);
        out << "PGA(Z): " << input.ZA / 100. << "; PGV(Z): " << input.ZV / 100.;
        out << "; PGD(Z): " << input.ZD / 100.;
        resultstr = out.str();
        out.str("");
        SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());
        out << "PGA(H): " << input.HA / 100. << "; PGV(H): " << input.HV / 100.;
        out << "; PGD(H): " << input.HD / 100.;
        resultstr = out.str();
        SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());
    }

    if ( inputs.empty() ) {
        SEISCOMP_LOG(_processingInfoChannel,
                     "End logging for event: %s", event->publicID().c_str());
        return;
    }

    // Grid search
    float mag = 0.5f;
    float minL = -1.0f;
    float minMag = mag;

    while ( mag <= 9.0f ) {
        float L = 0.0f;

        for ( size_t i = 0; i < inputs.size(); ++i ) {
            const VsInput &input = inputs[i];

            // Likelihood
            vs.setmag(mag);
            L += vs.likelihood(input.ZA, input.ZV, input.ZD, input.HA, input.HV,
                               input.HD, input.PSclass, input.SOILclass, input.lat,
                               input.lon);
        }

        if ( minL < 0 || minL > L ) {
            minL = L;
            minMag = mag;
        }

        mag += 0.01f;
    }

    // calculate the median of all station magnitudes
    size_t size = inputs.size();
    double *mestarray = new double[size];

    for ( size_t i = 0; i < size; ++i ) {
        const VsInput &input = inputs[i];
        mestarray[i] = input.mest;
    }

    nth_element(mestarray, mestarray + size / 2, mestarray + size);
    stmag = mestarray[size / 2];
    delete[] mestarray;

    // TODO: Define errors
    evt->vsMagnitude = minMag;
    evt->vsStationCount = inputs.size();


    if ( _timeline.pollbuffer(evt->lat, evt->lon,evt->dthresh,evt->allThresholdStationsCount) != no_problem) {
        SEISCOMP_WARNING("Problems in the buffer polling function.");
        return;
    }


    // Use quality control functions to decide if the event is valid
    evt->isValid = false;
    double deltamag;
    double deltapick;
    if ( isEventValid(stmag, evt, evt->likelihood, deltamag, deltapick) ) {
        evt->isValid = true;
    }

    // logging
    string resultstr;
    ostringstream out;
    out.precision(2);
    out.setf(ios::fixed, ios::floatfield);
    out << "VS-mag: " << minMag << "; median single-station-mag: " << stmag;
    out << "; lat: " << evt->lat << "; lon: " << evt->lon;
    out << "; depth : " << evt->dep << " km";
    resultstr = out.str();
    out.str("");
    SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());

    out << "creation time: " << _currentTime.toString("%FT%T.%2fZ");
    out << "; origin time: " << evt->time.toString("%FT%T.%2fZ");
    Core::TimeSpan difftime = _currentTime - evt->time;
    Core::Time now = Core::Time::GMT();
    Core::TimeSpan difftime_oa = now - evt->originArrivalTime;
    Core::TimeSpan difftime_ct = now - evt->originCreationTime;
    out << "; t-diff: " << difftime.length();
    out.precision(3);
    out << "; time since origin arrival: " << difftime_oa.length();
    out << "; time since origin creation: " << difftime_ct.length();
    resultstr = out.str();
    out.str("");
    SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());

    out << "# picked stations: " << evt->pickedStationsCount; // all stations with picks
    out << "; # envelope streams: " << _timeline.StreamCount(); // all stations with envelope streams
    resultstr = out.str();
    out.str("");
    SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());

    // distance threshold for delta-pick quality criteria
    out.precision(2);
    out << "Distance threshold (dt): " << Math::Geo::deg2km(evt->dthresh)
        << " km";
    out << "; # picked stations < dt: " << evt->pickedThresholdStationsCount;
    out << "; # envelope streams < dt: " << evt->allThresholdStationsCount;
    resultstr = out.str();
    out.str("");
    SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());

    if (evt->pickedStationsCount > evt->vsStationCount) {
        out << "Stations not used for VS-mag: ";
        // find picked stations that don't contribute to the VS magnitude
        Timeline::StationList &sl = evt->pickedStations;
        for (Timeline::StationList::iterator it=sl.begin(); it!=sl.end(); ++it) {
            if ( evt->stations.find(*it) == evt->stations.end() || unused.find(*it) != unused.end()) {
                out << (*it).first << '.' << (*it).second << ' ';
            }
        }
        resultstr = out.str();
        out.str("");
        SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());
    }

    out.precision(3);
    out << "Magnitude check: " << deltamag << "; Arrivals check: " << deltapick;
    out << "; Azimuthal gap: " << evt->azGap;
    resultstr = out.str();
    out.str("");
    SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());

    out.precision(2);
    out << "likelihood: " << evt->likelihood;
    resultstr = out.str();
    out.str("");
    SEISCOMP_LOG(_processingInfoChannel, "%s", resultstr.c_str());

    SEISCOMP_LOG(_processingInfoChannel,
                 "End logging for event: %s", event->publicID().c_str());
}