void CalculateAmplitudes::addProcessor(Processing::AmplitudeProcessor *proc, const DataModel::Pick *pick, int c) { static const char *names[3] = {"vertical", "first horizontal", "second horizontal"}; char component; ThreeComponents tc; try { tc = Client::Inventory::Instance()->getThreeComponents(pick); } catch ( ... ) {} WaveformStreamID cwid = pick->waveformID(); if ( tc.comps[ThreeComponents::Component(c)] == NULL ) component = '\0'; else { cwid.setChannelCode(tc.comps[ThreeComponents::Component(c)]->code()); component = *cwid.channelCode().rbegin(); } std::string streamID = waveformIDToStdString(cwid); int row = addProcessingRow(streamID, proc->type()); if ( component == '\0' ) { setError(row, QString("no %1 component found").arg(names[c])); return; } StreamMap::iterator it = _streams.find(streamID); if ( it != _streams.end() ) proc->streamConfig((WaveformProcessor::Component)c) = *it->second; else { Processing::StreamPtr stream = new Processing::Stream; stream->init(cwid.networkCode(), cwid.stationCode(), cwid.locationCode(), cwid.channelCode(), pick->time().value()); _streams[streamID] = stream; proc->streamConfig((WaveformProcessor::Component)c) = *stream; } if ( proc->streamConfig((WaveformProcessor::Component)c).gain == 0.0 ) { setError(row, "no gain found"); return; } if ( proc->status() != WaveformProcessor::WaitingForData ) { setError(row, QString("%1 (%2)").arg(proc->status().toString()).arg(proc->statusValue(), 0, 'f', 2)); return; } else setError(row, proc->status().toString()); _rows.insert(TableRowMap::value_type(proc, row)); }
void CalculateAmplitudes::subscribeData(Processing::AmplitudeProcessor *proc, const DataModel::Pick *pick, int c) { if ( proc->streamConfig((WaveformProcessor::Component)c).code().empty() ) return; if ( proc->streamConfig((WaveformProcessor::Component)c).gain == 0.0 ) return; WaveformStreamID cwid = pick->waveformID(); cwid.setChannelCode(proc->streamConfig((WaveformProcessor::Component)c).code()); std::string streamID = waveformIDToStdString(cwid); pair<ProcessorMap::iterator, bool> handle = _processors.insert(ProcessorMap::value_type(streamID, ProcessorSlot())); if ( handle.second ) _thread->addStream(cwid.networkCode(), cwid.stationCode(), cwid.locationCode(), cwid.channelCode()); handle.first->second.push_back(proc); // Add processors timewindow to global acquisition timewindow _timeWindow = _timeWindow | proc->safetyTimeWindow(); }
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> void Envelope::addProcessor(SensorLocation *loc, const WaveformStreamID &id, const Core::Time ×tamp, const char *type, const char *short_type) { DataModel::ThreeComponents tc; DataModel::WaveformStreamID tmp(id); try { DataModel::getThreeComponents( tc, loc, id.channelCode().c_str(), timestamp ); } catch ( exception &e ) { SEISCOMP_ERROR("%s: cannot query three components: %s: " "%s channels not used", Private::toStreamID(tmp).c_str(), e.what(), type); } for ( int i = 0; i < 3; ++i ) { if ( tc.comps[i] == NULL ) continue; tmp.setChannelCode(tc.comps[i]->code()); if ( !_streamFirewall.isAllowed(Private::toStreamID(tmp)) ) continue; SEISCOMP_INFO("%s: +%s", Private::toStreamID(tmp).c_str(), short_type); recordStream()->addStream(tmp.networkCode(), tmp.stationCode(), tmp.locationCode(), tmp.channelCode()); ProcessorPtr proc = new Processor(_config.baselineCorrectionBufferLength); switch ( i ) { case ThreeComponents::Vertical: proc->setUsedComponent(Processing::WaveformProcessor::Vertical); proc->setName("Z"); break; case ThreeComponents::FirstHorizontal: proc->setUsedComponent(Processing::WaveformProcessor::FirstHorizontal); proc->setName("H1"); break; case ThreeComponents::SecondHorizontal: proc->setUsedComponent(Processing::WaveformProcessor::SecondHorizontal); proc->setName("H2"); break; } Processing::StreamPtr stream = new Processing::Stream; stream->init(tmp.networkCode(), tmp.stationCode(), tmp.locationCode(), tmp.channelCode(), timestamp); proc->streamConfig((Processing::WaveformProcessor::Component)proc->usedComponent()) = *stream; proc->setWaveformID(tmp); proc->setSaturationThreshold(_config.saturationThreshold); proc->useVSFilterImplementation(!_config.useSC3Filter); if ( proc->streamConfig((Processing::WaveformProcessor::Component)proc->usedComponent()).gain == 0.0 ) { SEISCOMP_WARNING("%s: -%s: gain not defined (= 0.0)", short_type, Private::toStreamID(tmp).c_str()); continue; } proc->setPublishFunction(boost::bind(&Envelope::emitResult, this, _1, _2, _3, _4, _5, _6)); _processors[Private::toStreamID(tmp)] = proc; } }
/*! \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()); }