/*! \brief Save the VS Magnitude in the preferred origin of the event Update the preferred origin object of the event and send a message to the master so the magnitude can be saved to the database. \param event The sc3 event to which the magnitude belongs \param mag The magnitude to be added to the event \param stacnt Station Count (number of stations used to calculate the magnitude) */ void VsMagnitude::updateVSMagnitude(Event *event, VsEvent *vsevt) { SEISCOMP_DEBUG( "%s: %s: VS = %.4f", event->publicID().c_str(), _currentTime.toString("%FT%T.%fZ").c_str(), *vsevt->vsMagnitude); SEISCOMP_DEBUG("Update number is %d", vsevt->update); OriginPtr org = _cache.get<Origin>(event->preferredOriginID()); if ( org == NULL ) { 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; } Notifier::SetEnabled(true); _creationInfo.setCreationTime(_currentTime); _creationInfo.setModificationTime(Core::None); _creationInfo.setVersion(Core::toString(vsevt->update)); MagnitudePtr nmag = Magnitude::Create(); nmag->setMagnitude(RealQuantity(*vsevt->vsMagnitude)); nmag->setType("MVS"); nmag->setStationCount(vsevt->vsStationCount); nmag->setCreationInfo(_creationInfo); org->add(nmag.get()); for (StaMagArray::iterator it = vsevt->staMags.begin(); it != vsevt->staMags.end(); ++it) { const DataModel::StationMagnitude *staMag = (*it).get(); nmag->add(new StationMagnitudeContribution(staMag->publicID(),staMag->magnitude().value()- *vsevt->vsMagnitude,1.0)); } vsevt->staMags.clear(); /// set a comment containing the update number /// if the update numbers of two successive comments for the /// same event are identical signals the logging script that /// the event processing has finished setComments(nmag.get(), "update", vsevt->update); /// set the likelihood of the estimate as a comment setComments(nmag.get(), "likelihood", vsevt->likelihood); /// send the message containing the vs magnitude and the /// two comments to scmaster Core::MessagePtr msg = Notifier::GetMessage(); if ( connection() && msg ) connection()->send(msg.get()); Notifier::SetEnabled(false); }
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> bool AmpTool::run() { if ( !_originID.empty() ) { OriginPtr org = Origin::Cast(query()->getObject(Origin::TypeInfo(), _originID)); if ( !org ) { cerr << "Origin not found!" << endl; return false; } _fetchMissingAmplitudes = false; query()->loadArrivals(org.get()); process(org.get()); return true; } if ( !_strTimeWindowStartTime.empty() || !_strTimeWindowEndTime.empty() ) { if ( database() == NULL ) { cerr << "No database currently active for time window reprocessing" << endl; return false; } Core::Time startTime, endTime; if ( !_strTimeWindowStartTime.empty() && !startTime.fromString(_strTimeWindowStartTime.c_str(), "%F %T") ) { cerr << "Invalid start time: " << _strTimeWindowStartTime << endl; return false; } if ( !_strTimeWindowEndTime.empty() && !endTime.fromString(_strTimeWindowEndTime.c_str(), "%F %T") ) { cerr << "Invalid end time: " << _strTimeWindowEndTime << endl; return false; } std::string dbQuery; dbQuery += "select PPick." + _T("publicID") + ", Pick.* from Pick,PublicObject as PPick,Amplitude " "where Pick._oid=PPick._oid and Amplitude." + _T("pickID") + "=PPick." + _T("publicID"); if ( startTime.valid() ) dbQuery += " and Pick." + _T("time_value") + ">='" + startTime.toString("%F %T") + "'"; if ( endTime.valid() ) dbQuery += " and Pick." + _T("time_value") + "<'" + endTime.toString("%F %T") + "'"; dbQuery += " group by Amplitude." + _T("pickID"); if ( !commandline().hasOption("commit") ) _testMode = true; EventParametersPtr ep; if ( _testMode ) ep = new EventParameters; typedef list<PickPtr> PickList; PickList picks; cerr << "Collecting picks ... " << flush; DatabaseIterator db_it = query()->getObjectIterator(dbQuery, Pick::TypeInfo()); ObjectPtr obj; while ( obj = db_it.get() ) { Pick *pick = static_cast<Pick*>(obj.get()); try { pick->waveformID().networkCode(); pick->waveformID().stationCode(); pick->waveformID().locationCode(); pick->waveformID().channelCode(); pick->time().value(); } catch ( ... ) { continue; } ++db_it; picks.push_back(pick); if ( ep ) ep->add(pick); } db_it.close(); cerr << picks.size() << endl; _report << std::endl; _report << "Reprocessing report" << std::endl; _report << "-------------------" << std::endl; _report << " + Picks" << std::endl; int errors = 0; int ampsRecomputed = 0; int messagesSent = 0; int idx = 1; for ( PickList::iterator it = picks.begin(); it != picks.end(); ++it, ++idx ) { PickPtr pick = *it; SingleAmplitudeMap dbAmps; if ( isExitRequested() ) break; // Clear all processors _processors.clear(); // Clear all station time windows _stationRequests.clear(); _report << " + " << pick->publicID() << std::endl; cerr << "[" << idx << "]" << " " << (*it)->publicID() << endl; db_it = query()->getAmplitudesForPick((*it)->publicID()); while ( obj = db_it.get() ) { Amplitude *amp = static_cast<Amplitude*>(obj.get()); cerr << " [" << setw(10) << left << amp->type() << "] "; AmplitudeProcessorPtr proc = AmplitudeProcessorFactory::Create(amp->type().c_str()); if ( !proc ) { if ( _amplitudeTypes.find(amp->type()) == _amplitudeTypes.end() ) cerr << "No processor"; else { cerr << "No processor but enabled"; ++errors; } } else { cerr << "Fetch data"; dbAmps[amp->type()] = amp; proc->setTrigger(pick->time().value()); proc->setReferencingPickID(pick->publicID()); proc->setPublishFunction(boost::bind(&AmpTool::storeLocalAmplitude, this, _1, _2)); _report << " + Data" << std::endl; addProcessor(proc.get(), pick.get(), None, None); } cerr << endl; ++db_it; } db_it.close(); cerr << " --------------------------------" << endl; if ( _stationRequests.empty() ) continue; for ( RequestMap::iterator it = _stationRequests.begin(); it != _stationRequests.end(); ++it ) { StationRequest &req = it->second; for ( WaveformIDSet::iterator wit = req.streams.begin(); wit != req.streams.end(); ++wit ) { const WaveformStreamID &wsid = *wit; recordStream()->addStream(wsid.networkCode(), wsid.stationCode(), wsid.locationCode(), wsid.channelCode(), req.timeWindow.startTime(), req.timeWindow.endTime()); } _report << " + TimeWindow (" << it->first << "): " << req.timeWindow.startTime().toString("%F %T") << ", " << req.timeWindow.endTime().toString("%F %T") << std::endl; } _reprocessMap.clear(); readRecords(false); list<AmplitudePtr> updates; for ( AmplitudeMap::iterator it = dbAmps.begin(); it != dbAmps.end(); ++it ) { AmplitudePtr oldAmp = it->second; AmplitudePtr newAmp = _reprocessMap[oldAmp->type()]; cerr << " [" << setw(10) << left << oldAmp->type() << "] " << oldAmp->amplitude().value() << " "; if ( newAmp ) { if ( newAmp->amplitude().value() != oldAmp->amplitude().value() ) { *oldAmp = *newAmp; if ( ep ) ep->add(oldAmp.get()); else updates.push_back(oldAmp); cerr << "-> " << newAmp->amplitude().value(); } else cerr << " no changes"; ++ampsRecomputed; } else { cerr << "-"; ++errors; } cerr << endl; } if ( !updates.empty() ) { if ( !_testMode ) { NotifierMessagePtr nmsg = new NotifierMessage; for ( list<AmplitudePtr>::iterator it = updates.begin(); it != updates.end(); ++it ) { nmsg->attach(new Notifier("EventParameters", OP_UPDATE, it->get())); } connection()->send(nmsg.get()); ++messagesSent; if ( messagesSent % 100 == 0 ) sync(); } else { cerr << " --------------------------------" << endl; cerr << " Test mode, nothing sent" << endl; } } } if ( ep ) { IO::XMLArchive ar; ar.create("-"); ar.setFormattedOutput(true); ar << ep; ar.close(); } cerr << "----------------------------------" << endl; cerr << "Recomputed " << ampsRecomputed << " amplitudes" << endl; cerr << "Sent " << messagesSent << " messages" << endl; if ( errors ) cerr << errors << " errors occurred, check the processing log" << endl; return true; } if ( !_epFile.empty() ) { _fetchMissingAmplitudes = false; // Disable database setDatabase(NULL); _cache.setDatabaseArchive(NULL); IO::XMLArchive ar; if ( !ar.open(_epFile.c_str()) ) { SEISCOMP_ERROR("Failed to open %s", _epFile.c_str()); return false; } ar >> _ep; ar.close(); if ( !_ep ) { SEISCOMP_ERROR("No event parameters found in %s", _epFile.c_str()); return false; } if ( commandline().hasOption("reprocess") ) { for ( size_t i = 0; i < _ep->amplitudeCount(); ++i ) { AmplitudePtr amp = _ep->amplitude(i); feed(amp.get()); } } for ( size_t i = 0; i < _ep->originCount(); ++i ) { OriginPtr org = _ep->origin(i); SEISCOMP_INFO("Processing origin %s", org->publicID().c_str()); process(org.get()); } ar.create("-"); ar.setFormattedOutput(true); ar << _ep; ar.close(); _ep = NULL; return true; }
/*! \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()); }
/*! \brief Extract information from event object. \param event Seiscomp3 type Event */ void VsMagnitude::handleEvent(Event *event) { _cache.feed(event); double dmax = 0; // dmax distance of the furthest picked station from the epicenter double davg = 0; // average distance of all picked stations from the epicenter double dsum = 0; // sum of distances double dthresh; /// get the preferred origin of the event 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; } /// search for the corresponding VsEvent in the cache VsEventPtr vsevent; VsEvents::iterator it = _events.find(event->publicID()); if ( it == _events.end() ) { /// if not found, create a new VsEvent vsevent = new VsEvent; if ( _expirationTimeReference == "ct" ) { vsevent->expirationTime = _currentTime + Core::TimeSpan(_eventExpirationTime, 0); } else if ( _expirationTimeReference == "ot" ) { vsevent->expirationTime = org->time().value() + Core::TimeSpan(_eventExpirationTime, 0); if ( !(_currentTime < vsevent->expirationTime) ) return; } // set time to track how long it takes to estimate the magnitude // and how long it took for the origin to arrive vsevent->originArrivalTime = Core::Time::GMT(); vsevent->originCreationTime = org->creationInfo().creationTime(); // check whether event has been published already EventIDBuffer::iterator cev = _publishedEvents.find(event->publicID()); if ( cev != _publishedEvents.end() ) { SEISCOMP_DEBUG("Event %s has already been published", event->publicID().c_str()); return; } vsevent->update = -1; vsevent->maxAzGap = _maxazgap; /// ...and attach it to the cache (_events) _events[event->publicID()] = vsevent; } /// if found, use the existing one else vsevent = it->second; /// Populate the vsevent with data from the preferred origin of the sc3 event vsevent->lat = org->latitude().value(); vsevent->lon = org->longitude().value(); vsevent->dep = org->depth().value(); vsevent->time = org->time().value(); if ( _expirationTimeReference == "ot" ) vsevent->expirationTime = org->time().value() + Core::TimeSpan(_eventExpirationTime, 0); /// Generate some statistics for later use in delta-pick quality measure Timeline::StationList pickedThresholdStations; // all picked stations at a limited distance from the epicenter vsevent->pickedStations.clear(); SEISCOMP_DEBUG("Number of arrivals in origin %s: %d", org->publicID().c_str(), (int)org->arrivalCount()); vsevent->stations.clear(); for ( size_t i = 0; i < org->arrivalCount(); ++i ) { Arrival *arr = org->arrival(i); PickPtr pick = _cache.get<Pick>(arr->pickID()); if ( !pick ) { SEISCOMP_DEBUG("cache.get<Pick>(\"%s\") failed to return pick", arr->pickID().c_str()); continue; } Timeline::StationID id(pick->waveformID().networkCode(), pick->waveformID().stationCode()); // if the station is not yet in the pickedStations set if ( vsevent->pickedStations.find(id) == vsevent->pickedStations.end() ) { double dist = arr->distance(); if ( dist > dmax ) dmax = dist; vsevent->pickedStations.insert(id); dsum += dist; } // if Station already used, continue if ( vsevent->stations.find(id) != vsevent->stations.end() ) continue; VsTimeWindow &tw = vsevent->stations[id]; tw.setStartTime(pick->time().value() - Core::TimeSpan(_twstarttime, 0)); tw.setEndTime(pick->time().value() + Core::TimeSpan(_twendtime, 0)); tw.setPickTime(pick->time().value()); // Todo: make sure that at least three seconds of data after the pick // are available } // count the number of arrivals with epicentral distance (in degrees) // less than the threshold for use in deltaPick() vsevent->pickedStationsCount = vsevent->pickedStations.size(); davg = dsum / (double) vsevent->pickedStationsCount; // calculate threshold dthresh = 0.5 * (dmax + davg); for ( size_t i = 0; i < org->arrivalCount(); i++ ) { Arrival *arr = org->arrival(i); PickPtr pick = _cache.get<Pick>(arr->pickID()); if ( !pick ) { SEISCOMP_DEBUG("cache.get<Pick>(\"%s\") failed to return pick", arr->pickID().c_str()); continue; } Timeline::StationID id(pick->waveformID().networkCode(), pick->waveformID().stationCode()); if ( pick && arr->distance() < dthresh ) { // if the pickedThresholdStations.insert(id); } } vsevent->pickedThresholdStationsCount = pickedThresholdStations.size(); vsevent->dthresh = dthresh; SEISCOMP_DEBUG("dmax; %f, davg: %f, dthresh: %f", dmax, davg, dthresh); // Get azimuthal gap vsevent->azGap = org->quality().azimuthalGap(); }