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); }
/*! \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()); }