[OpendTect_Developers] using parallel task in OpendTect
Ranojay Sen
ranojay.sen at dgbes.com
Mon Jan 23 07:03:30 CET 2012
Dear All,
OpendTect code has some inbuilt tools to handle tasks parallelly
using multiple threads. In order to use this functionality we have to
derive a class from ParallelTask and overrule some virtual functions and
write the piece of code which we think should run in different threads,
and we are ready to go. The beauty of this class is that it handles all
the complexities of the thread handling and provides a simple
user-friendly interface.
In seismic interpretation horizons are everywhere, and we compute
several features based on horizons. I was exploring what if we could use
muti-threading //to make(or compute ) horizons. Usually when we do any
computation on a horizon a HorSampling Iterator is used which iterates
through all the BinIDs sequentially starting from start inline-crossline
position. I have made a class from parallel task which will divide the
horizon in small pieces and distribute each of these pieces to a thread
so that each thread will process a small part of the HorSampling data
simultaneously. This division of threads will totally be controlled by
this class depending on the number of CPU cores on the system. Lets
start with the class, first derive a class from ParallelTask as
mentioned above, now overrule the virtual functions. I guess it is time
for a code example. This code below is very simple and self explanatory,
I will explain some parts explicitly.
#include "arrayndimpl.h"
#include "cubesampling.h"
#include "emmanager.h"
#include "emhorizon3d.h"
#include "moddepmgr.h"
#include "progressmeter.h"
#include "ranges.h"
#include "statrand.h"
#include "executor.h"
class HorizonBuilder : public ParallelTask
{
public:
HorizonBuilder( EM::Horizon3D* hor3d, int startinl,
int startcrl, float z, int nrinl,
int nrcrl, std::ostream& strm )
: hor3d_(hor3d)
, startinl_(startinl)
, startcrl_(startcrl)
, zed_(z)
, nrinl_(nrinl)
, nrcrl_(nrcrl)
, totalnr_(nrinl)
, progress_(*new TextStreamProgressMeter(strm)) //
constuctor with a EM::Horizon3D* and range details.
{
hor3d_->enableGeometryChecks( false );
setProgressMeter( &progress_ );
}
~HorizonBuilder()
{}
virtual od_int64 nrIterations() const { return totalnr_; } //
overrule the nrIteration so that the class can decide how many positions
to process.
virtual bool doPrepare( int ) //create the horsampling based
on the ranges, and fill in the horizon with undefined values.
{
hs_.start.inl = startinl_;
hs_.start.crl = startcrl_;
hs_.stop.inl = startinl_ + nrinl_;
hs_.stop.crl = startcrl_ + nrcrl_;
depthvals_ = new Array2DImpl<float>( hs_.nrInl()-1,
hs_.nrCrl() );
const EM::SectionID sid = hor3d_->sectionID( 0 );
hor3d_->geometry().sectionGeometry(sid)->
expandWithUdf( hs_.start, hs_.stop );
return true;
}
protected:
virtual bool doWork( od_int64 start, od_int64 stop, int id )
// This is the function which will split up in multiple threads. and
will start a new thread with different HorSampling //for each thread.
{
HorSampling hrg( false );
hrg.start.inl = start + startinl_;
hrg.start.crl = startcrl_;
hrg.stop.inl = stop + startinl_;
hrg.stop.crl = startcrl_ + nrcrl_;
horIter( hrg, id );
return true;
}
void horIter( const HorSampling& hrg, float id ) // This
function will actually run in parallel filling up its positions with new
z values.
{
int nrdone = 0;
HorSamplingIterator iter( hrg );
BinID bid = hrg.start;
const float z = id/100;
do
{
int inlidx = hs_.inlIdx( bid.inl );
int crlidx = hs_.crlIdx( bid.crl );
depthvals_->set( inlidx, crlidx, zed_-z );
nrdone++;
if ( nrdone>1000 )
{
addToNrDone( nrdone );
nrdone= 0;
}
} while ( iter.next(bid) );
addToNrDone( nrdone );
}
virtual bool doFinish( bool success ) // finish up
{
const EM::SectionID sid = hor3d_->sectionID( 0 );
const bool ret = hor3d_->setArray2D( *depthvals_, sid,
true, 0 );
return ret;
}
EM::Horizon3D* hor3d_;
od_int64 totalnr_;
int startinl_;
int startcrl_;
float zed_;
int nrinl_;
int nrcrl_;
ProgressMeter& progress_;
HorSampling hs_;
Array2DImpl<float>* depthvals_;
};
int main( int argc, char ** argv ) // The main function doing few
initialisations.
{
OD::ModDeps().ensureLoaded( "AllNonUi" );
const EM::ObjectID objid = EM::EMM().createObject(
EM::Horizon3D::typeStr(),
"Case_test" );
EM::EMObject* emobj = EM::EMM().getObject( objid );
mDynamicCastGet(EM::Horizon3D*,hor3d,emobj);
if ( !hor3d )
return 1;
std::ostream& strm( std::cout );
HorizonBuilder builder( hor3d, 0, 0, 1.5, 1000, 1200, strm ); //
create the executor
if ( !builder.execute() ) // execute
return 1;
strm << "\n\nSaving new horizon " << hor3d->name() << std::endl;
PtrMan<Executor> saver = hor3d->saver();
return saver->execute( &strm );
return 0;
}
So that's it, a simple class to implement multi-threading. I must thank
Kris (**Kristofer Tingdahl ) here for his guidance and inspiration for
preparing this code. As always questions and comments are welcome.
Regards
Ranojay
--
Ranojay Sen
dGB Earth Sciences (India)
304, Gateway Plaza,
Hiranandani Gardens - Powai
Mumbai 400 076 - India -
Tel. +91 22 25704984 - Fax +91 22 25704977
www.dgbes.com www.opendtect.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.opendtect.org/pipermail/developers/attachments/20120123/e301436d/attachment.html>
More information about the Developers
mailing list