/** Populates the vector of event data buffers (vectors), vector of event source objects, vector of event source fields and the vector of event datasets by querying the messages on InputVariables. */ void NSDFWriter::openEventData(const Eref &eref) { if (filehandle_ <= 0){ return; } for (unsigned int ii = 0; ii < eventInputs_.size(); ++ii){ stringstream path; path << eref.objId().path() << "/" << "eventInput[" << ii << "]"; ObjId inputObj = ObjId(path.str()); Element * el = inputObj.element(); const DestFinfo * dest = static_cast<const DestFinfo*>(el->cinfo()->findFinfo("input")); vector < ObjId > src; vector < string > srcFields; el->getMsgSourceAndSender(dest->getFid(), src, srcFields); if (src.size() > 1){ cerr << "NSDFWriter::openEventData - only one source can be connected to an eventInput" <<endl; } else if (src.size() == 1){ eventSrcFields_.push_back(srcFields[0]); eventSrc_.push_back(src[0].path()); events_.resize(eventSrc_.size()); stringstream path; path << src[0].path() << "." << srcFields[0]; hid_t dataSet = getEventDataset(src[0].path(), srcFields[0]); eventDatasets_.push_back(dataSet); } else { cerr <<"NSDFWriter::openEventData - cannot handle multiple connections at single input." <<endl; } } }
void Shell::doMove( Id orig, ObjId newParent ) { if ( orig == Id() ) { cout << "Error: Shell::doMove: Cannot move root Element\n"; return; } if ( newParent.element() == 0 ) { cout << "Error: Shell::doMove: Cannot move object to null parent \n"; return; } if ( Neutral::isDescendant( newParent, orig ) ) { cout << "Error: Shell::doMove: Cannot move object to descendant in tree\n"; return; } const string& name = orig.element()->getName(); if ( Neutral::child( newParent.eref(), name ) != Id() ) { stringstream ss; ss << "Shell::doMove: Object with same name already present: '" << newParent.path() << "/" << name << "'. Move failed."; warning( ss.str() ); return; } SetGet2< Id, ObjId >::set( ObjId(), "move", orig, newParent ); // innerMove( orig, newParent ); }
void remoteFieldGetVec( const Eref& e, unsigned int bindIndex, vector< double >& getRecvBuf ) { static ObjId oi( 3 ); static PostMaster* p = reinterpret_cast< PostMaster* >( oi.data() ); p->remoteFieldGetVec( e, bindIndex, getRecvBuf ); }
void Shell::recvGet( const Eref& e, const Qinfo* q, PrepackedBuffer pb ) { if ( myNode_ == 0 ) { if ( gettingVector_ ) { ObjId tgt = q->src(); // unsigned int linearIndex = q->src().eref().index().value(); unsigned int linearIndex = tgt.element()->dataHandler()->linearIndex( tgt.dataId ); if ( linearIndex >= getBuf_.size() ) { if ( linearIndex >= getBuf_.capacity() ) getBuf_.reserve( linearIndex * 2 ); getBuf_.resize( linearIndex + 1 ); } assert ( linearIndex < getBuf_.size() ); double*& c = getBuf_[ linearIndex ]; c = new double[ pb.dataSize() ]; memcpy( c, pb.data(), pb.dataSize() * sizeof( double ) ); // cout << myNode_ << ":" << q->threadNum() << ": Shell::recvGet[" << linearIndex << "]= (" << pb.dataSize() << ", " << *c << ")\n"; } else { assert ( getBuf_.size() == 1 ); double*& c = getBuf_[ 0 ]; c = new double[ pb.dataSize() ]; memcpy( c, pb.data(), pb.dataSize() * sizeof( double ) ); handleAck( 0, OkStatus ); } ++numGetVecReturns_; } }
void remoteGetVec( const Eref& e, unsigned int bindIndex, vector< vector< double > >& getRecvBuf, vector< unsigned int >& numOnNode ) { static ObjId oi( 3 ); static PostMaster* p = reinterpret_cast< PostMaster* >( oi.data() ); p->remoteGetVec( e, bindIndex, getRecvBuf, numOnNode ); }
ObjId OneToOneDataIndexMsg::findOtherEnd( ObjId f ) const { if ( f.element() == e1() ) return ObjId( e2()->id(), f.dataIndex ); else if ( f.element() == e2() ) return ObjId( e1()->id(), f.dataIndex ); return ObjId( 0, BADINDEX ); }
// Utility function: return the compartment in which the specified // object is located. // Simply traverses the tree toward the root till it finds a // compartment. Pools use a special msg, but this works for reacs too. ObjId getCompt( Id id ) { ObjId pa = Neutral::parent( id.eref() ).id; if ( pa == ObjId() ) return pa; else if ( pa.element()->cinfo()->isA( "ChemCompt" ) ) return pa; return getCompt( pa ); }
void EndoMesh::setSurround( const Eref& e, ObjId v ) { if ( !v.element()->cinfo()->isA( "ChemCompt" ) ) { cout << "Warning: 'surround' may only be set to an object of class 'ChemCompt'\n"; cout << v.path() << " is of class " << v.element()->cinfo()->name() << endl; return; } surround_ = v; parent_ = reinterpret_cast< const MeshCompt* >( v.data() ); }
ObjId OneToAllMsg::findOtherEnd( ObjId f ) const { if ( f.element() == e1() ) { if ( f.dataIndex == i1_ ) return ObjId( e2()->id(), 0 ); } else if ( f.element() == e2() ) { return ObjId( e1()->id(), i1_ ); } return ObjId( 0, BADINDEX ); }
// static function, executed by the Synapse Element when a message is // dropped from the Element. Contracts the parent synapse array to fit. // Typically the SynHandler won't resize, easier to just leave an // unused entry. Could even reuse if a synapse is added later, but all // this policy is independent of the Synapse class. void Synapse::dropMsgCallback( const Eref& e, const string& finfoName, ObjId msg, unsigned int msgLookup ) { if ( finfoName == "addSpike" ) { ObjId pa = Neutral::parent( e ); SynHandlerBase* sh = reinterpret_cast< SynHandlerBase* >( pa.data() ); sh->dropSynapse( msgLookup ); } }
ObjId OneToAllMsg::findOtherEnd( ObjId f ) const { if ( f.id() == e1() ) { if ( f.dataId == i1_ ) return ObjId( e2()->id(), 0 ); else return ObjId( e2()->id(), DataId::bad() ); } else if ( f.id() == e2() ) { return ObjId( e1()->id(), i1_ ); } return ObjId::bad(); }
// static function, executed by the Synapse Element when a message is // added to the Element. Expands the parent synapse array to fit. void Synapse::addMsgCallback( const Eref& e, const string& finfoName, ObjId msg, unsigned int msgLookup ) { if ( finfoName == "addSpike" ) { ObjId pa = Neutral::parent( e ); SynHandlerBase* sh = reinterpret_cast< SynHandlerBase* >( pa.data() ); unsigned int synapseNumber = sh->addSynapse(); SetGet2< unsigned int, unsigned int >::set( msg, "fieldIndex", msgLookup, synapseNumber ); } }
void dispatchBuffers( const Eref& e, HopIndex hopIndex ) { static ObjId oi( 3 ); static PostMaster* p = reinterpret_cast< PostMaster* >( oi.data() ); if ( Shell::numNodes() == 1 ) return; if ( hopIndex.hopType() == MooseSetHop || hopIndex.hopType() == MooseGetHop ) { p->dispatchSetBuf( e ); } if ( hopIndex.hopType() == MooseSetVecHop ) { p->dispatchSetBuf( e ); } // More complicated stuff for get operations. }
void HDF5DataWriter::recvData(const Eref&e, ObjId src, const double* start, unsigned int num ) { string path = src.path(); if (nodemap_.find(path) == nodemap_.end()){ // first time call, initialize entries in map hid_t dataid = get_dataset(path); if (dataid < 0){ cerr << "Warning: could not create data set for " << path << endl; } nodemap_[path] = dataid; datamap_[path] = vector<double>(); } const double * end = start + num; // append only the new data. old_size is guaranteed to be 0 on // write and the table vecs will also be cleared. datamap_[path].insert(datamap_[path].end(), start, end); SetGet0::set(src, "clearVec"); //Unsure what this is for. // #ifndef NDEBUG // // debug leftover entries coming from table // cout << "HDF5DataWriter::recvData: vec_size=" << vec_size << endl; // cout << "HDF5DataWriter::recvData: dataSize=" << pb.dataSize() << endl; // cout << "HDF5DataWriter::recvData: numEntries=" << pb.numEntries() << endl; // cout << "HDF5DataWriter::recvData: size=" << pb.size() << endl; // cout << "HDF5DataWriter::recvData: data()" << endl; // for (int ii = 0; ii <= vec_size; ++ii){ // cout << ii << "\t" << pb.data()[ii] << endl; // } // #endif }
void Neutral::setName( const Eref& e, string name ) { if ( e.id().value() <= 3 ) { cout << "Warning: Neutral::setName on '" << e.id().path() << "'.Cannot rename core objects\n"; return; } ObjId pa = parent( e ); Id sibling = Neutral::child( pa.eref(), name ); if ( sibling == Id() ) { // OK, no existing object with same name. e.element()->setName( name ); } else { cout << "Warning: Neutral::setName: an object with the name '" << name << "'\n already exists on the same parent. Not changed\n"; } }
// static function bool Neutral::isDescendant( Id me, Id ancestor ) { static const Finfo* pf = neutralCinfo->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); Eref e = me.eref(); while ( e.element()->id() != Id() && e.element()->id() != ancestor ) { ObjId mid = e.element()->findCaller( pafid ); assert( mid != ObjId() ); ObjId fid = Msg::getMsg( mid )->findOtherEnd( e.objId() ); e = fid.eref(); } return ( e.element()->id() == ancestor ); }
double* addToBuf( const Eref& er, HopIndex hopIndex, unsigned int size ) { static ObjId oi( 3 ); static PostMaster* p = reinterpret_cast< PostMaster* >( oi.data() ); if ( hopIndex.hopType() == MooseSendHop ) { return p->addToSendBuf( er, hopIndex.bindIndex(), size ); } else if ( hopIndex.hopType() == MooseSetHop || hopIndex.hopType() == MooseSetVecHop ) { p->clearPendingSetGet(); // Cannot touch set buffer if pending. return p->addToSetBuf( er, hopIndex.bindIndex(), size, hopIndex.hopType() ); } else if ( hopIndex.hopType() == MooseTestHop ) { return addToTestBuf( er, hopIndex.bindIndex(), size ); } assert( 0 ); // Should not get here. return 0; }
void NSDFWriter::writeModelTree() { vector< string > tokens; ObjId mRoot(modelRoot_); string rootPath = MODELTREEPATH + string("/") + mRoot.element()->getName(); hid_t rootGroup = require_group(filehandle_, rootPath); hid_t tmp; htri_t exists; herr_t status; deque<Id> nodeQueue; deque<hid_t> h5nodeQueue; nodeQueue.push_back(mRoot); h5nodeQueue.push_back(rootGroup); // TODO: need to clarify what happens with array elements. We can // have one node per vec and set a count field for the number of // elements while (nodeQueue.size() > 0){ ObjId node = nodeQueue.front(); nodeQueue.pop_front(); hid_t prev = h5nodeQueue.front();; h5nodeQueue.pop_front(); vector < Id > children; Neutral::children(node.eref(), children); for ( unsigned int ii = 0; ii < children.size(); ++ii){ string name = children[ii].element()->getName(); // skip the system elements if (children[ii].path() == "/Msgs" || children[ii].path() == "/clock" || children[ii].path() == "/classes" || children[ii].path() == "/postmaster"){ continue; } exists = H5Lexists(prev, name.c_str(), H5P_DEFAULT); if (exists > 0){ tmp = H5Gopen2(prev, name.c_str(), H5P_DEFAULT); } else { tmp = H5Gcreate2(prev, name.c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); } writeScalarAttr< string >(tmp, "uid", children[ii].path()); nodeQueue.push_back(children[ii]); h5nodeQueue.push_back(tmp); } status = H5Gclose(prev); } }
void Shell::destroy( const Eref& e, ObjId oid) { Neutral *n = reinterpret_cast< Neutral* >( e.data() ); assert( n ); // cout << myNode_ << ": Shell::destroy done for element id: " << eid << ", name = " << eid.element()->getName() << endl; n->destroy( oid.eref(), 0 ); if ( cwe_.id == oid.id ) cwe_ = ObjId(); }
Id ReadCell::startGraftCell( const string& cellPath ) { /* * If path exists, return with error. This will also catch the case where * cellPath is "/", and we will not have to check for this separately * later. */ Id cellId( cellPath ); if ( cellId.path() == cellPath ) { cerr << "Warning: ReadCell: cell '" << cellPath << "' already exists.\n"; cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; return Id(); } ObjId parentObjId; string cellName; string::size_type pos_1 = cellPath.find_first_of( "/" ); string::size_type pos_2 = cellPath.find_last_of( "/" ); if ( pos_1 != 0 ) { cerr << "Error: ReadCell: *start_cell should be given absolute path.\n"; cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; return Id(); } if ( pos_2 == 0 ) { parentObjId = ObjId("/"); cellName = cellPath.substr( 1 ); } else { string parentPath = cellPath.substr( 0, pos_2 ); parentObjId = ObjId( parentPath ); if ( parentObjId.bad() ) { cerr << "Error: ReadCell: cell path '" << cellPath << "' not found.\n"; cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; return Id(); } cellName = cellPath.substr( pos_2 + 1 ); } unsigned int size = 1; return shell_->doCreate( "Compartment", parentObjId, cellName, size, MooseGlobal ); }
// Static function string Neutral::path( const Eref& e ) { static const Finfo* pf = neutralCinfo->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); vector< ObjId > pathVec; ObjId curr = e.objId(); stringstream ss; pathVec.push_back( curr ); while ( curr.id != Id() ) { ObjId mid = curr.eref().element()->findCaller( pafid ); if ( mid == ObjId() ) { cout << "Error: Neutral::path:Cannot follow msg of ObjId: " << e.objId() << " for func: " << pafid << endl; break; } curr = Msg::getMsg( mid )->findOtherEnd( curr ); pathVec.push_back( curr ); } if ( pathVec.size() <= 1 ) return "/"; for ( unsigned int i = 1; i < pathVec.size(); ++i ) { ss << "/"; ObjId& oid = pathVec[ pathVec.size() - i - 1 ]; ss << oid.element()->getName(); if ( !oid.element()->hasFields() ) ss << "[" << oid.dataIndex << "]"; /* if ( !oid.element()->hasFields() ) ss << "[" << oid.dataIndex << "]"; if ( oid.element()->numData() > 1 ) ss << "[" << oid.dataIndex << "]"; */ } // Append braces if Eref was for a fieldElement. This should // work even if it is off-node. if ( e.element()->hasFields() ) { ss << "[" << e.fieldIndex() << "]"; } return ss.str(); }
ObjId SparseMsg::findOtherEnd( ObjId f ) const { if ( f.element() == e1() ) { const unsigned int* entry; const unsigned int* colIndex; unsigned int num = matrix_.getRow( f.dataIndex, &entry, &colIndex ); if ( num > 0 ) { // Return the first matching entry. return ObjId( e2()->id(), colIndex[0] ); } return ObjId( 0, BADINDEX ); } else if ( f.element() == e2() ) { // Bad! Slow! Avoid! vector< unsigned int > entry; vector< unsigned int > rowIndex; unsigned int num = matrix_.getColumn( f.dataIndex, entry, rowIndex ); if ( num > 0 ) { // Return the first matching entry. return ObjId( e1()->id(), DataId( rowIndex[0] ) ); } } return ObjId( 0, BADINDEX ); }
/** * Reads in SynChans and SpikeGens. * * Unlike Compartments, HHChannels, etc., neither of these are zombified. * In other words, their fields are not managed by HSolve, and their "process" * functions are invoked to do their calculations. For SynChans, the process * calls are made by their respective clocks, and hence the process message is * not dropped. On the other hand, we drop the SpikeGen process messages here, * and explicitly call the SpikeGen process() from the HSolve via a pointer. */ void HSolveActive::readSynapses() { vector< Id > spikeId; vector< Id > synId; vector< Id >::iterator syn; vector< Id >::iterator spike; SynChanStruct synchan; for ( unsigned int ic = 0; ic < nCompt_; ++ic ) { synId.clear(); HSolveUtils::synchans( compartmentId_[ ic ], synId ); for ( syn = synId.begin(); syn != synId.end(); ++syn ) { synchan.compt_ = ic; synchan.elm_ = *syn; synchan_.push_back( synchan ); } static const Finfo* procDest = SpikeGen::initCinfo()->findFinfo( "process"); assert( procDest ); const DestFinfo* df = dynamic_cast< const DestFinfo* >( procDest ); assert( df ); spikeId.clear(); HSolveUtils::spikegens( compartmentId_[ ic ], spikeId ); // Very unlikely that there will be >1 spikegens in a compartment, // but lets take care of it anyway. for ( spike = spikeId.begin(); spike != spikeId.end(); ++spike ) { spikegen_.push_back( SpikeGenStruct( &V_[ ic ], spike->eref() ) ); ObjId mid = spike->element()->findCaller( df->getFid() ); if ( ! mid.bad() ) Msg::deleteMsg( mid ); } } }
/** Utility function to delete incoming messages on orig. To be used in zombifying elements. */ void HSolve::deleteIncomingMessages( Element * orig, const string finfo) { const DestFinfo * concenDest = dynamic_cast<const DestFinfo*>(orig->cinfo()->findFinfo(finfo)); assert(concenDest); ObjId mid = orig->findCaller(concenDest->getFid()); while (! mid.bad()) { const Msg * msg = Msg::getMsg(mid); assert(msg); ObjId other = msg->findOtherEnd(orig->id()); Element * otherEl = other.id.element(); if (otherEl && HSolve::handledClasses().find(otherEl->cinfo()->name()) != HSolve::handledClasses().end()) { Msg::deleteMsg(mid); } else { break; // Have to do this otherwise it is an infinite loop } mid = orig->findCaller(concenDest->getFid()); } }
/** * Adds a typical channel to a compartment: * - Connects up the 'channel' message between chan and compt. * - Sets the Gbar field on the channel. * * Typical channels currently are: HHChannel, HHChannel2D and SynChan. All of * these have the same "channel" interface, and have a "Gbar" field. */ bool ReadCell::addCanonicalChannel( Id compt, Id chan, double value, double dia, double length ) { string className = chan.element()->cinfo()->name(); if ( className == "HHChannel" || className == "HHChannel2D" || className == "SynChan" || className == "NMDAChan" ) { ObjId mid = shell_->doAddMsg( "Single", compt, "channel", chan, "channel" ); if ( mid.bad() ) cout << "failed to connect message from compt " << compt << " to channel " << chan << endl; if ( value > 0 ) { value *= calcSurf( length, dia ); } else { value = -value; } if ( !graftFlag_ ) ++numChannels_; return Field< double >::set( chan, "Gbar", value ); } return 0; }
bool Shell::innerMove( Id orig, ObjId newParent ) { static const Finfo* pf = Neutral::initCinfo()->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); static const Finfo* f1 = Neutral::initCinfo()->findFinfo( "childOut" ); assert( !( orig == Id() ) ); assert( !( newParent.element() == 0 ) ); ObjId mid = orig.element()->findCaller( pafid ); Msg::deleteMsg( mid ); Msg* m = new OneToAllMsg( newParent.eref(), orig.element(), 0 ); assert( m ); if ( !f1->addMsg( pf, m->mid(), newParent.element() ) ) { cout << "move: Error: unable to add parent->child msg from " << newParent.element()->getName() << " to " << orig.element()->getName() << "\n"; return 0; } return 1; }
/** * Static utility function. Attaches child element to parent element. * Must only be called from functions executing in parallel on all nodes, * as it does a local message addition * MsgIndex is needed to be sure that the same msg identifies parent-child * connection on all nodes. */ bool Shell::adopt( ObjId parent, Id child, unsigned int msgIndex ) { static const Finfo* pf = Neutral::initCinfo()->findFinfo( "parentMsg" ); // static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); // static const FuncId pafid = pf2->getFid(); static const Finfo* f1 = Neutral::initCinfo()->findFinfo( "childOut" ); assert( !( child.element() == 0 ) ); assert( !( child == Id() ) ); assert( !( parent.element() == 0 ) ); Msg* m = new OneToAllMsg( parent.eref(), child.element(), msgIndex ); assert( m ); // cout << myNode_ << ", Shell::adopt: mid = " << m->mid() << ", pa =" << parent << "." << parent()->getName() << ", kid=" << child << "." << child()->getName() << "\n"; if ( !f1->addMsg( pf, m->mid(), parent.element() ) ) { cout << "move: Error: unable to add parent->child msg from " << parent.element()->getName() << " to " << child.element()->getName() << "\n"; return 0; } return 1; }
ObjId Neutral::parent( ObjId oid ) { static const Finfo* pf = neutralCinfo->findFinfo( "parentMsg" ); static const DestFinfo* pf2 = dynamic_cast< const DestFinfo* >( pf ); static const FuncId pafid = pf2->getFid(); if ( oid.id == Id() ) { cout << "Warning: Neutral::parent: tried to take parent of root\n"; return Id(); } ObjId mid = oid.element()->findCaller( pafid ); assert( mid != ObjId() ); ObjId pa = Msg::getMsg( mid )->findOtherEnd( oid ); return pa; }
/// non-static func. Returns the Id found by traversing the specified path. ObjId Shell::doFind( const string& path ) const { if ( path == "/" || path == "/root" ) return ObjId(); ObjId curr; vector< string > names; vector< unsigned int > indices; bool isAbsolute = chopPath( path, names, indices ); assert( names.size() == indices.size() ); if ( !isAbsolute ) curr = cwe_; for ( unsigned int i = 0; i < names.size(); ++i ) { if ( names[i] == "." ) { } else if ( names[i] == ".." ) { curr = Neutral::parent( curr.eref() ); } else { ObjId pa = curr; curr = Neutral::child( curr.eref(), names[i] ); if ( curr == ObjId() ) // Neutral::child returned Id(), ie, bad. return ObjId( 0, BADINDEX ); if ( curr.element()->hasFields() ) { curr.dataIndex = pa.dataIndex; curr.fieldIndex = indices[i]; } else { curr.dataIndex = indices[i]; if ( curr.element()->numData() <= curr.dataIndex ) return ObjId( 0, BADINDEX ); } } } assert( curr.element() ); if ( curr.element()->numData() <= curr.dataIndex ) return ObjId( 0, BADINDEX ); if ( curr.fieldIndex > 0 && !curr.element()->hasFields() ) return ObjId( 0, BADINDEX ); return curr; }
void ReadCell::addChannelMessage( Id chan ) { /* * Get child objects of type Mstring, named addmsg1, 2, etc. * These define extra messages to be assembled at setup. * Similar to what was done with GENESIS. */ vector< Id > kids; Neutral::children( chan.eref(), kids ); Shell *shell = reinterpret_cast< Shell* >( Id().eref().data() ); Id cwe = shell->getCwe(); shell->setCwe( chan ); for ( vector< Id >::iterator i = kids.begin(); i != kids.end(); ++i ) { // Ignore kid if its name does not begin with "addmsg".. const string& name = i->element()->getName(); if ( name.find( "addmsg", 0 ) != 0 ) continue; string s = Field< string >::get( *i, "value" ); vector< string > token; tokenize( s, " ", token ); assert( token.size() == 4 ); ObjId src = shell->doFind( token[0] ); ObjId dest = shell->doFind( token[2] ); // I would like to assert, or warn here, but there are legitimate // cases where not all possible messages are actually available // to set up. So I just bail. if ( src.bad() || dest.bad()) { #ifndef NDEBUG /* cout << "ReadCell::addChannelMessage( " << chan.path() << "): " << name << " " << s << ": Bad src " << src << " or dest " << dest << endl; */ #endif continue; } ObjId mid = shell->doAddMsg( "single", src, token[1], dest, token[3] ); assert( !mid.bad()); } shell->setCwe( cwe ); }