void OneToOneMsg::targets( vector< vector< Eref > > & v) const { unsigned int n = e1_->numData(); v.resize( e1_->numData() ); if ( e2_->hasFields() ) { if ( Eref( e2_, i2_ ).isDataHere() ) { assert( i2_ > e2_->localDataStart() ); unsigned int nf = e2_->numField( i2_ - e2_->localDataStart() ); if ( n > nf ) n = nf; for ( unsigned int i = 0; i < n; ++i ) v[i].resize( 1, Eref( e2_, i2_, i ) ); } else { // Don't know target node # of entries, so send all. unsigned int start = e1_->localDataStart(); unsigned int end = start + e1_->numLocalData(); for ( unsigned int i = start; i < end; ++i ) { v[i].resize( 1, Eref( e2_, i2_, i ) ); } } } else { if ( n > e2_->numData() ) n = e2_->numData(); for ( unsigned int i = 0; i < n; ++i ) { v[i].resize( 1, Eref( e2_, i ) ); } } }
void ZombieHandler::forall( const OpFunc* f, Element* e, const Qinfo* q, const double* arg, unsigned int argSize, unsigned int numArgs ) const { // This should be relevant. But I still have to define threadStart_ // Find which thread parent is willing to handle // I still don't know how to get at the parent DataId. I need it. if ( parent_->execThread( q->threadNum(), 0 ) ) { // On this thread, figure out which index range we should use. // We have start and end, so that is fine. // Iterate through the opfunc for all of these. if ( numArgs <= 1 ) { for( unsigned int i = start_; i != end_; ++i ) { f->op( Eref( e, i ), q, arg ); } } else { unsigned int argOffset = argSize * start_; unsigned int maxOffset = argSize * numArgs; for( unsigned int i = start_; i != end_; ++i ) { f->op( Eref( e, i ), q, arg + argOffset ); argOffset += argSize; if ( argOffset >= maxOffset ) argOffset = 0; } } } }
Eref OneToAllMsg::firstTgt( const Eref& src ) const { if ( src.element() == e1_ ) return Eref( e2_, 0 ); else if ( src.element() == e2_ ) return Eref( e1_, i1_ ); return Eref( 0, 0 ); }
Eref SingleMsg::firstTgt( const Eref& src ) const { if ( src.element() == e1_ ) return Eref( e2_, i2_, f2_ ); else if ( src.element() == e2_ ) return Eref( e1_, i1_ ); return Eref( 0, 0 ); }
/** * This is a little tricky because we might be mapping between * data entries and field entries here. * May wish also to apply to exec operations. * At this point, the effect of trying to go between regular * data entries and field entries is undefined. */ Eref OneToOneDataIndexMsg::firstTgt( const Eref& src ) const { if ( src.element() == e1_ ) { return Eref( e2_, src.dataIndex(), 0 ); } else if ( src.element() == e2_ ) { return Eref( e1_, src.dataIndex() ); } return Eref( 0, 0 ); }
/** * This is a little tricky because we might be mapping between * data entries and field entries here. * May wish also to apply to exec operations. * At this point, the effect of trying to go between regular * data entries and field entries is undefined. */ Eref OneToOneMsg::firstTgt( const Eref& src ) const { if ( src.element() == e1_ ) { if ( e2_->hasFields() ) return Eref( e2_, i2_, src.dataIndex() ); else return Eref( e2_, src.dataIndex(), 0 ); } else if ( src.element() == e2_ ) { return Eref( e1_, src.dataIndex() ); } return Eref( 0, 0 ); }
// This puts the special HopFuncs into the MsgDigest. Furthermore, the // Erefs to which they point are the originating Eref instance on the // remote node. This Eref will then invoke its own send call to complete // the message transfer. void Element::putOffNodeTargetsInDigest( unsigned int srcNum, vector< vector< bool > >& targetNodes ) // targetNodes[srcDataId][node] { if ( msgBinding_[ srcNum ].size() == 0 ) return; const MsgFuncBinding& mfb = msgBinding_[ srcNum ][0]; const Msg* msg = Msg::getMsg( mfb.mid ); const OpFunc* func; if ( msg->e1() == this ) { func = msg->e2()->cinfo()->getOpFunc( mfb.fid ); } else { func = msg->e1()->cinfo()->getOpFunc( mfb.fid ); } assert( func ); // How do I eventually destroy these? const OpFunc* hop = func->makeHopFunc( srcNum ); for ( unsigned int i = 0; i < numData(); ++i ) { vector< Eref > tgts; for ( unsigned int j = 0; j < Shell::numNodes(); ++j ) { if ( targetNodes[i][j] ) tgts.push_back( Eref( this, i, j ) ); // This is a hack. I encode the target node # in the FieldIndex // and the originating Eref in the remainder of the Eref. // The HopFunc has to extract both these things to push into // the correct SendBuffer. } if ( tgts.size() > 0 ) { vector< MsgDigest >& md = msgDigest_[ msgBinding_.size() * i + srcNum ]; md.push_back( MsgDigest( hop, tgts ) ); } } }
void OneToAllMsg::sources( vector< vector < Eref > >& v ) const { // Same single source for all targets. v.clear(); vector< Eref > temp( 1, Eref( e1_, i1_ ) ); v.assign( e2_->numData(), temp ); }
Eref SparseMsg::firstTgt( const Eref& src ) const { if ( matrix_.nEntries() == 0 ) return Eref( 0, 0 ); if ( src.element() == e1_ ) { const unsigned int* fieldIndex; const unsigned int* colIndex; unsigned int n = matrix_.getRow( src.dataIndex(), &fieldIndex, &colIndex ); if ( n != 0 ) { return Eref( e2_, colIndex[0], fieldIndex[0] ); } } else if ( src.element() == e2_ ) { return Eref( e1_, 0 ); } return Eref( 0, 0 ); }
void OneToOneDataIndexMsg::targets( vector< vector< Eref > > & v) const { unsigned int n = e1_->numData(); v.resize( e1_->numData() ); if ( n > e2_->numData() ) n = e2_->numData(); for ( unsigned int i = 0; i < n; ++i ) { v[i].resize( 1, Eref( e2_, i ) ); } }
void ZombieFunction::zombify( Element* orig, const Cinfo* zClass, Id ksolve, Id dsolve ) { //cout << "ZombieFunction::zombify: " << orig->id().path() << endl; if ( orig->cinfo() == zClass ) return; // unsigned int start = orig->localDataStart(); unsigned int num = orig->numLocalData(); if ( num == 0 ) return; if ( num > 1 ) cout << "ZombieFunction::zombify: Warning: ZombieFunction doesn't\n" "handle volumes yet. Proceeding without this.\n"; Function* f = reinterpret_cast< Function *>( Eref( orig, 0 ).data() ); Function temp = *f; orig->zombieSwap( zClass ); if ( zClass == ZombieFunction::initCinfo() ) { // call SetSolver ZombieFunction* zf = reinterpret_cast< ZombieFunction *>( Eref( orig, 0 ).data() ); *zf = *static_cast< ZombieFunction* >(&temp); zf->setSolver( ksolve, dsolve ); } else { Function* nf = reinterpret_cast< Function *>(Eref( orig, 0 ).data()); *nf = temp; } /* // We can swap the class because the class data is identical, just // the moose expr and process handlers are different. if ( orig->cinfo() == ZombieFunction::initCinfo() ) { // unzombify orig->replaceCinfo( Function::initCinfo() ); } else { // zombify orig->replaceCinfo( ZombieFunction::initCinfo() ); ZombieFunction* zf = reinterpret_cast< ZombieFunction *>( Eref( orig, 0 ).data() ); zf->setSolver( ksolve, dsolve ); } */ }
Msg* OneToAllMsg::copy( Id origSrc, Id newSrc, Id newTgt, FuncId fid, unsigned int b, unsigned int n ) const { const Element* orig = origSrc(); if ( n <= 1 ) { OneToAllMsg* ret = 0; if ( orig == e1() ) { ret = new OneToAllMsg( Msg::nextMsgId(), Eref( newSrc(), i1_ ), newTgt() ); ret->e1()->addMsgAndFunc( ret->mid(), fid, b ); } else if ( orig == e2() ) { ret = new OneToAllMsg( Msg::nextMsgId(), Eref( newTgt(), i1_ ), newSrc() ); ret->e2()->addMsgAndFunc( ret->mid(), fid, b ); } else { assert( 0 ); } return ret; } else { // Here we need a SliceMsg which goes from one 2-d array to another. cout << "Error: OneToAllMsg::copy: SliceToSliceMsg not yet implemented\n"; return 0; } }
// We don't permit e1 to have fields at this point. void OneToOneMsg::sources( vector< vector< Eref > > & v) const { v.resize( 0 ); unsigned int n = e1_->numData(); if ( e2_->hasFields() ) { if ( Eref( e2_, i2_ ).isDataHere() ) { assert( i2_ > e2_->localDataStart() ); unsigned int nf = e2_->numField( i2_ - e2_->localDataStart() ); if ( n > nf ) n = nf; v.resize( n ); for ( unsigned int i = 0; i < n; ++i ) { v[i].resize( 1, Eref( e1_, i ) ); } } } else { if ( n > e2_->numData() ) n = e2_->numData(); v.resize( e2_->numData() ); for ( unsigned int i = 0; i < n; ++i ) { v[i].resize( 1, Eref( e1_, i ) ); } } }
/** * Need to revisit to handle nodes */ void OneToAllMsg::exec( const Qinfo* q, const double* arg, FuncId fid ) const { if ( q->src().element() == e1_ ) { if ( q->src().dataId == i1_ ) { const OpFunc* f = e2_->cinfo()->getOpFunc( fid ); e2_->dataHandler()->forall( f, e2_, q, arg, 1, 0 ); } } else { if ( e1_->dataHandler()->execThread( q->threadNum(), i1_ ) ) { const OpFunc* f = e1_->cinfo()->getOpFunc( fid ); f->op( Eref( e1_, i1_ ), q, arg ); } } }
void fillErefsFromMatrix( const SparseMatrix< unsigned int >& matrix, vector< vector < Eref > >& v, Element* e1, Element* e2 ) { v.clear(); v.resize( e1->numData() ); assert( e1->numData() == matrix.nRows() ); assert( e2->numData() == matrix.nColumns() ); for ( unsigned int i = 0; i < e1->numData(); ++i ) { const unsigned int* entry; const unsigned int* colIndex; unsigned int num = matrix.getRow( i, &entry, &colIndex ); v[i].resize( num ); for ( unsigned int j = 0; j < num; ++j ) { v[i][j] = Eref( e2, colIndex[j], entry[j] ); } } }
void HSolveHub::manageCompartments() { const vector< Id >& idlist = integ_->getCompartments(); vector< Element* > elist; idlist2elist( idlist, elist ); const vector< vector< Id > >& externalChannelIds = integ_->getExternalChannels(); vector< Element* > extChanList; const Finfo* initFinfo = initCompartmentCinfo()->findFinfo( "init" ); vector< Element* >::const_iterator i; for ( i = elist.begin(); i != elist.end(); i++ ) { zombify( hub_, *i, compartmentSolveFinfo, compartmentZombieFinfo ); // Compartment receives 2 shared messages from Tick's "process" Eref( *i ).dropAll( initFinfo->msg() ); redirectDynamicMessages( *i ); } /* * Redirecting dest/shared messages */ for ( unsigned int ic = 0; ic < elist.size(); ic++ ) { // The 'retain' flag at the end is 1: we do not delete the original // message to the compartment. redirectDestMessages( hub_, elist[ ic ], hubCompartmentInjectFinfo, compartmentInjectFinfo, ic, compartmentInjectMap_, &elist, 0, 1 ); extChanList.clear(); idlist2elist( externalChannelIds[ ic ], extChanList ); redirectDestMessages( hub_, elist[ ic ], hubCompartmentChannelFinfo, compartmentChannelFinfo, ic, compartmentChannelMap_, &elist, &extChanList, 1 ); } }
void OneToAllMsg::targets( vector< vector< Eref > >& v ) const { v.clear(); v.resize( e1_->numData() ); v[i1_].resize( 1, Eref( e2_, ALLDATA ) ); }
void SingleMsg::sources( vector< vector< Eref > >& v ) const { v.clear(); v.resize( e2_->numData() ); v[i2_].resize( 1, Eref( e1_, i1_ ) ); }
void SingleMsg::targets( vector< vector< Eref > >& v ) const { v.clear(); v.resize( e1_->numData() ); v[i1_].resize( 1, Eref( e2_, i2_, f2_ ) ); }
void testBioScan( ) { cout << "\nTesting Bioscan" << flush; bool success; Element* n = Neutral::create( "Neutral", "n", Element::root()->id(), Id::scratchId() ); /** * First we test the functions which return the compartments linked to a * given compartment: adjacent(), and children(). * * A small tree is created for this: * * c0 * L c1 * L c2 * L c3 * L c4 * L c5 * * (c0 is the parent of c1. c1 is the parent of c2, c3, c4, c5.) */ Element* c[ 6 ]; c[ 0 ] = Neutral::create( "Compartment", "c0", n->id(), Id::scratchId() ); c[ 1 ] = Neutral::create( "Compartment", "c1", n->id(), Id::scratchId() ); c[ 2 ] = Neutral::create( "Compartment", "c2", n->id(), Id::scratchId() ); c[ 3 ] = Neutral::create( "Compartment", "c3", n->id(), Id::scratchId() ); c[ 4 ] = Neutral::create( "Compartment", "c4", n->id(), Id::scratchId() ); c[ 5 ] = Neutral::create( "Compartment", "c5", n->id(), Id::scratchId() ); success = Eref( c[ 0 ] ).add( "axial", c[ 1 ], "raxial" ); ASSERT( success, "Linking compartments" ); success = Eref( c[ 1 ] ).add( "axial", c[ 2 ], "raxial" ); ASSERT( success, "Linking compartments" ); success = Eref( c[ 1 ] ).add( "axial", c[ 3 ], "raxial" ); ASSERT( success, "Linking compartments" ); success = Eref( c[ 1 ] ).add( "axial", c[ 4 ], "raxial" ); ASSERT( success, "Linking compartments" ); success = Eref( c[ 1 ] ).add( "axial", c[ 5 ], "raxial" ); ASSERT( success, "Linking compartments" ); vector< Id > found; unsigned int nFound; /** Testing version 1 of BioScan::adjacent. * It finds all neighbours of given compartment. */ // Neighbours of c0 nFound = BioScan::adjacent( c[ 0 ]->id(), found ); ASSERT( nFound == found.size(), "Finding adjacent compartments" ); // c1 is adjacent ASSERT( nFound == 1, "Finding adjacent compartments" ); ASSERT( found[ 0 ] == c[ 1 ]->id(), "Finding adjacent compartments" ); // Neighbours of c1 found.clear(); nFound = BioScan::adjacent( c[ 1 ]->id(), found ); ASSERT( nFound == 5, "Finding adjacent compartments" ); // c0 is adjacent success = find( found.begin(), found.end(), c[ 0 ]->id() ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); // c2 - c5 are adjacent for ( int i = 2; i < 6; i++ ) { success = find( found.begin(), found.end(), c[ i ]->id() ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); } // Neighbours of c2 found.clear(); nFound = BioScan::adjacent( c[ 2 ]->id(), found ); // c1 is adjacent ASSERT( nFound == 1, "Finding adjacent compartments" ); ASSERT( found[ 0 ] == c[ 1 ]->id(), "Finding adjacent compartments" ); /** Testing version 2 of BioScan::adjacent. * It finds all but one neighbours of given compartment. * The the second argument to 'adjacent' is the one that is excluded. */ // Neighbours of c1 (excluding c0) found.clear(); nFound = BioScan::adjacent( c[ 1 ]->id(), c[ 0 ]->id(), found ); ASSERT( nFound == 4, "Finding adjacent compartments" ); // c2 - c5 are adjacent for ( int i = 2; i < 6; i++ ) { success = find( found.begin(), found.end(), c[ i ]->id() ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); } // Neighbours of c1 (excluding c2) found.clear(); nFound = BioScan::adjacent( c[ 1 ]->id(), c[ 2 ]->id(), found ); ASSERT( nFound == 4, "Finding adjacent compartments" ); // c0 is adjacent success = find( found.begin(), found.end(), c[ 0 ]->id() ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); // c3 - c5 are adjacent for ( int i = 3; i < 6; i++ ) { success = find( found.begin(), found.end(), c[ i ]->id() ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); } // Neighbours of c2 (excluding c1) found.clear(); nFound = BioScan::adjacent( c[ 2 ]->id(), c[ 1 ]->id(), found ); // None adjacent, if c1 is excluded ASSERT( nFound == 0, "Finding adjacent compartments" ); // Neighbours of c2 (excluding c3) found.clear(); nFound = BioScan::adjacent( c[ 2 ]->id(), c[ 3 ]->id(), found ); // c1 is adjacent, while c3 is not even connected ASSERT( nFound == 1, "Finding adjacent compartments" ); ASSERT( found[ 0 ] == c[ 1 ]->id(), "Finding adjacent compartments" ); /** Testing BioScan::children. * It finds all compartments which are dests for the "axial" message. */ // Children of c0 found.clear(); nFound = BioScan::children( c[ 0 ]->id(), found ); ASSERT( nFound == 1, "Finding child compartments" ); // c1 is a child ASSERT( found[ 0 ] == c[ 1 ]->id(), "Finding child compartments" ); // Children of c1 found.clear(); nFound = BioScan::children( c[ 1 ]->id(), found ); ASSERT( nFound == 4, "Finding child compartments" ); // c2 - c5 are c1's children for ( int i = 2; i < 6; i++ ) { success = find( found.begin(), found.end(), c[ i ]->id() ) != found.end(); ASSERT( success, "Finding child compartments" ); } // Children of c2 found.clear(); nFound = BioScan::children( c[ 2 ]->id(), found ); // c2 has no children ASSERT( nFound == 0, "Finding child compartments" ); // Clean up set( n, "destroy" ); }
Eref Id::eref() const { return Eref( elements()[ id_ ], 0 ); // return Eref( elements()[ id_ ], index_ ); }