Seiscomp3系统的代码量比较可观的,用代码统计工具算了一下,大概有49万行代码,主要以C/C++和python为主。如果没有C/C++基础的话,有不小的难度。最近因为工作的需要对Seiscop3的源码进行了部分走读,对系统的架构有一些了解,但对于代码细节还有待研究,此博客的目的主要是记录学习过程,希望给后来的同学一点启示,少走些弯路。当然了,因为本人的水平有限,记录的内容会有不少错误,也希望各位看官指出错误,并告知我。
正是因为本系统的代码量庞大,研究Seiscomp3源码需要一个切入口,我选取的切入口,是源码中关于振幅和震级的测试例程。代码路径/seiscomp3-master/src/trunk/plugins/magnitudes/nuttli/test。主程序的入口在amplitudes.cpp中。
第一步,了解测试程序的结构。
此程序模块框图:
输入是包括三个文件:Charlevoix_MN2.4.mseed、Charlevoix_MN2.4.xml、inventory.xml。
这三个文件的路径在test所在的同级文件夹下面。
输出是Charlevoix_MN2.4_test.xml,xml文件里面包含振幅和震级。
第二步,源码分析
int main(int argc, char **argv) {
TestApp test(argc, argv);
return test();
}
程序入口,TestApp类继承自Client::Application类,在Application类中运算符重载了(),test()调用了父类的函数Application::operator()()-->Application::exec()-->run(),需要注意是此处的run重载了父类的Application::run(),程序运行时优先调用子类的run()函数。
以下代码有些难理解
int i = 0;
for ( AmplitudeMap::iterator it = originalAmplitudes.begin();
it != originalAmplitudes.end(); ++it, ++i ) {
Pick *pick = Pick::Find(it->second.first->pickID());
if ( pick == NULL ) {
SEISCOMP_WARNING("Ignoring amplitude %d: pick not found",
int(i));
continue;
}
DataModel::SensorLocation *loc = DataModel::getSensorLocation(inv, pick);
if ( loc == NULL ) {
SEISCOMP_WARNING("Ignoring amplitude %d: %s.%s.%s: sensor location not found", int(i),
pick->waveformID().networkCode().c_str(),
pick->waveformID().stationCode().c_str(),
pick->waveformID().locationCode().c_str());
continue;
}
DataModel::Stream *chan = DataModel::getVerticalComponent(
loc, pick->waveformID().channelCode().substr(0,2).c_str(),
pick->time().value()
);
if ( chan == NULL ) {
SEISCOMP_WARNING("Ignoring amplitude %d: vertical channel for %s.%s.%s not found",
int(i),
pick->waveformID().networkCode().c_str(),
pick->waveformID().stationCode().c_str(),
pick->waveformID().locationCode().c_str());
continue;
}
string sid = pick->waveformID().networkCode() + "." +
pick->waveformID().stationCode() + "." +
loc->code() + "." + chan->code();
if ( amplitudeProcStreamRoute.find(sid) != amplitudeProcStreamRoute.end() )
// Same stream id already used
continue;
// Inject sid into existing
Processing::Settings settings(configModuleName(),
pick->waveformID().networkCode(),
pick->waveformID().stationCode(),
pick->waveformID().locationCode(),
chan->code(),
&configuration(), NULL);
Processing::AmplitudeProcessorPtr proc;
proc = Processing::AmplitudeProcessorFactory::Create(AMP_TYPE);
proc->streamConfig(Processing::WaveformProcessor::VerticalComponent).init(chan);
proc->setTrigger(pick->time().value());
proc->setPick(pick);
if ( !proc->setup(settings) ) {
SEISCOMP_WARNING("Ignoring amplitude %d: processor for %s.%s.%s failed to setup: %s (%f)",
int(i),
pick->waveformID().networkCode().c_str(),
pick->waveformID().stationCode().c_str(),
pick->waveformID().locationCode().c_str(),
proc->status().toString(),
proc->statusValue());
continue;
}
proc->setEnvironment(origin.get(), loc, pick);
proc->computeTimeWindow();
if ( proc->isFinished() ) {
SEISCOMP_WARNING("Ignoring amplitude %d: processor %s.%s.%s has already finished: %s (%f)",
int(i),
pick->waveformID().networkCode().c_str(),
pick->waveformID().stationCode().c_str(),
pick->waveformID().locationCode().c_str(),
proc->status().toString(),
proc->statusValue());
continue;
}
proc->setPublishFunction(boost::bind(&TestApp::publishAmplitude, this, _1, _2));
amplitudeProcStreamRoute[sid] = proc;
amplitudeProcPickRoute[it->second.first->pickID()] = proc;
it->second.second = sid;
file.addStream(pick->waveformID().networkCode(),
pick->waveformID().stationCode(),
loc->code(), chan->code(),
proc->safetyTimeWindow().startTime(),
proc->safetyTimeWindow().endTime());
}
以上代码的大概意思是通过读取配置文件中的信息,去设置处理所需的参数,完成设置。要主要两个地方。
Processing::AmplitudeProcessorPtr proc;
proc = Processing::AmplitudeProcessorFactory::Create(AMP_TYPE);这两行代码很具有迷惑性,利用C++的多态特性,父类指针指向子类对象,完成对子类功能函数的调用。
还有就是proc->setPublishFunction(boost::bind(&TestApp::publishAmplitude, this, _1, _2));此函数利用了boost的特性,如果对boost不熟的话,只需知道此处设置了回调函数即可。
如果各位看官有任何问题,可以在评论区给我留言,我会尽力协助解决,谢谢。