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 ); }
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 ); }
/** * 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 ); } } }
/** * 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; }
/** 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()); } }
Id ReadCell::buildCompartment( const string& name, const string& parent, double x0, double y0, double z0, double x, double y, double z, double d, double& length, // Length is sent back. vector< string >& argv ) { static const Finfo* raxial2OutFinfo = SymCompartment::initCinfo()->findFinfo( "distalOut" ); /* * This section determines the parent compartment, to connect up with axial * messages. Here 'parent' refers to the biophysical relationship within * the neuron's tree, and not to the path hierarchy in the MOOSE element * tree. * * If the parent is specified as 'none', then the compartment is the root * of the cell's tree, and will not be connected axially to any compartments * except for its children, if any. */ Id parentId; if ( parent == "." ) { // Shorthand: use the previous compartment. parentId = lastCompt_; } else if ( parent == "none" || parent == "nil" ) { parentId = Id(); } else { string parentPath = currCell_.path() + "/" + parent; ObjId parentObjId = ObjId( parentPath ); if ( parentObjId.bad() ) { cerr << "Error: ReadCell: could not find parent compt '" << parent << "' for child '" << name << "'.\n"; cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; return ObjId(0, BADINDEX); } parentId = parentObjId; } //~ Id childId; //~ bool ret = lookupGet< Id, string >( //~ currCell_, "lookupChild", childId, name ); //~ assert( ret ); //~ if ( !childId.bad() ) { //~ if ( name[ name.length() - 1 ] == ']' ) { //~ string::size_type pos = name.rfind( '[' ); //~ if ( pos == string::npos ) { //~ cerr << "Error: ReadCell: bad child name:" << name << endl; //~ cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; //~ return 0; //~ } //~ unsigned int index = //~ atoi( name.substr( pos + 1, name.length() - pos ).c_str() ); //~ if ( childId.index() == index ) { //~ cerr << "Error: ReadCell: duplicate child on parent compt '" << //~ parent << "' for child '" << name << "'\n"; //~ cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; //~ return 0; //~ } //~ } else { //~ cerr << "Error: ReadCell: duplicate child on parent compt '" << //~ parent << "' for child '" << name << "'\n"; //~ cerr << "File: " << fileName_ << " Line: " << lineNum_ << endl; //~ return 0; //~ } //~ } unsigned int size = 1; Id compt; if ( graftFlag_ && ( parent == "none" || parent == "nil" ) ) { compt = currCell_; } else { if ( protoCompt_ != Id() ) { compt = shell_->doCopy( protoCompt_, currCell_, name, 1, // n: number of copies false, // toGlobal false // copyExtMsgs ); numCompartments_ += numProtoCompts_; numChannels_ += numProtoChans_; numOthers_ += numProtoOthers_; } else { string comptType = ( symmetricFlag_ ) ? "SymCompartment" : "Compartment"; compt = shell_->doCreate( comptType, currCell_, name, size, MooseGlobal ); if ( !graftFlag_ ) ++numCompartments_; } } lastCompt_ = compt; if ( parentId != Id()){ double px, py, pz; double dx, dy, dz; px = Field< double >::get( parentId, "x" ); py = Field< double >::get( parentId, "y" ); pz = Field< double >::get( parentId, "z" ); if ( !doubleEndpointFlag_ ) { x0 = px; y0 = py; z0 = pz; } if ( relativeCoordsFlag_ == 1 ) { x += px; y += py; z += pz; if ( doubleEndpointFlag_ ) { x0 += px; y0 += py; z0 += pz; } } dx = x - x0; dy = y - y0; dz = z - z0; length = sqrt( dx * dx + dy * dy + dz * dz ); if ( symmetricFlag_ ) { // Now find all sibling compartments on the same parent. // They must be connected up using 'sibling'. vector< Id > sibs; parentId.element()->getNeighbors( sibs, raxial2OutFinfo ); // Later put in the soma as a sphere, with its special msgs. shell_->doAddMsg( "Single", parentId, "distal", compt, "proximal" ); for ( vector< Id >::iterator i = sibs.begin(); i != sibs.end(); ++i ) { shell_->doAddMsg( "Single", compt, "sibling", *i, "sibling" ); } } else { shell_->doAddMsg( "Single", parentId, "axial", compt, "raxial" ); } } else { length = sqrt( x * x + y * y + z * z ); // or it could be a sphere. } double Cm, Rm, Ra; Cm = CM_ * calcSurf( length, d ); Rm = RM_ / calcSurf( length, d ); if ( length > 0 ) { Ra = RA_ * length * 4.0 / ( d * d * M_PI ); } else { Ra = RA_ * 8.0 / ( d * M_PI ); } // Set each of these to the other only if the only one set was other double eleak = ( erestFlag_ && !eleakFlag_ ) ? EREST_ACT_ : ELEAK_; double erest = ( !erestFlag_ && eleakFlag_ ) ? ELEAK_ : EREST_ACT_; Field< double >::set( compt, "x0", x0 ); Field< double >::set( compt, "y0", y0 ); Field< double >::set( compt, "z0", z0 ); Field< double >::set( compt, "x", x ); Field< double >::set( compt, "y", y ); Field< double >::set( compt, "z", z ); Field< double >::set( compt, "diameter", d ); Field< double >::set( compt, "length", length ); Field< double >::set( compt, "Rm", Rm ); Field< double >::set( compt, "Ra", Ra ); Field< double >::set( compt, "Cm", Cm ); Field< double >::set( compt, "initVm", erest ); Field< double >::set( compt, "Em", eleak ); Field< double >::set( compt, "Vm", erest ); return compt; }
void testHSolvePassive() { // TEST_BEGIN; Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() ); vector< int* > childArray; vector< unsigned int > childArraySize; /** * We test passive-cable solver for the following cell: * * Soma---> 15 - 14 - 13 - 12 * | | * | L 11 - 10 * | * L 16 - 17 - 18 - 19 * | * L 9 - 8 - 7 - 6 - 5 * | | * | L 4 - 3 * | * L 2 - 1 - 0 * * The numbers are the hines indices of compartments. Compartment X is the * child of compartment Y if X is one level further away from the soma (#15) * than Y. So #17 is the parent of #'s 2, 9 and 18. */ int childArray_1[ ] = { /* c0 */ -1, /* c1 */ -1, 0, /* c2 */ -1, 1, /* c3 */ -1, /* c4 */ -1, 3, /* c5 */ -1, /* c6 */ -1, 5, /* c7 */ -1, 4, 6, /* c8 */ -1, 7, /* c9 */ -1, 8, /* c10 */ -1, /* c11 */ -1, 10, /* c12 */ -1, /* c13 */ -1, 12, /* c14 */ -1, 11, 13, /* c15 */ -1, 14, 16, /* c16 */ -1, 17, /* c17 */ -1, 2, 9, 18, /* c18 */ -1, 19, /* c19 */ -1, }; childArray.push_back( childArray_1 ); childArraySize.push_back( sizeof( childArray_1 ) / sizeof( int ) ); /** * Cell 2: * * 3 * | * Soma---> 2 * / \ * / \ * 1 0 * */ int childArray_2[ ] = { /* c0 */ -1, /* c1 */ -1, /* c2 */ -1, 0, 1, 3, /* c3 */ -1, }; childArray.push_back( childArray_2 ); childArraySize.push_back( sizeof( childArray_2 ) / sizeof( int ) ); /** * Cell 3: * * 3 * | * 2 * / \ * / \ * 1 0 <--- Soma * */ int childArray_3[ ] = { /* c0 */ -1, 2, /* c1 */ -1, /* c2 */ -1, 1, 3, /* c3 */ -1, }; childArray.push_back( childArray_3 ); childArraySize.push_back( sizeof( childArray_3 ) / sizeof( int ) ); /** * Cell 4: * * 3 <--- Soma * | * 2 * / \ * / \ * 1 0 * */ int childArray_4[ ] = { /* c0 */ -1, /* c1 */ -1, /* c2 */ -1, 0, 1, /* c3 */ -1, 2, }; childArray.push_back( childArray_4 ); childArraySize.push_back( sizeof( childArray_4 ) / sizeof( int ) ); /** * Cell 5: * * 1 <--- Soma * | * 2 * / \ * 4 0 * / \ * 3 5 * */ int childArray_5[ ] = { /* c0 */ -1, /* c1 */ -1, 2, /* c2 */ -1, 0, 4, /* c3 */ -1, /* c4 */ -1, 3, 5, /* c5 */ -1, }; childArray.push_back( childArray_5 ); childArraySize.push_back( sizeof( childArray_5 ) / sizeof( int ) ); /** * Cell 6: * * 3 <--- Soma * L 4 * L 6 * L 5 * L 2 * L 1 * L 0 * */ int childArray_6[ ] = { /* c0 */ -1, /* c1 */ -1, /* c2 */ -1, /* c3 */ -1, 4, /* c4 */ -1, 0, 1, 2, 5, 6, /* c5 */ -1, /* c6 */ -1, }; childArray.push_back( childArray_6 ); childArraySize.push_back( sizeof( childArray_6 ) / sizeof( int ) ); /** * Cell 7: Single compartment */ int childArray_7[ ] = { /* c0 */ -1, }; childArray.push_back( childArray_7 ); childArraySize.push_back( sizeof( childArray_7 ) / sizeof( int ) ); /** * Cell 8: 3 compartments; soma is in the middle. */ int childArray_8[ ] = { /* c0 */ -1, /* c1 */ -1, 0, 2, /* c2 */ -1, }; childArray.push_back( childArray_8 ); childArraySize.push_back( sizeof( childArray_8 ) / sizeof( int ) ); /** * Cell 9: 3 compartments; first compartment is soma. */ int childArray_9[ ] = { /* c0 */ -1, 1, /* c1 */ -1, 2, /* c2 */ -1, }; childArray.push_back( childArray_9 ); childArraySize.push_back( sizeof( childArray_9 ) / sizeof( int ) ); //////////////////////////////////////////////////////////////////////////// // Run tests //////////////////////////////////////////////////////////////////////////// /* * Solver instance. */ HSolvePassive HP; /* * This is the full reference matrix which will be compared to its sparse * implementation. */ vector< vector< double > > matrix; /* * Model details. */ double dt = 1.0; vector< TreeNodeStruct > tree; vector< double > Em; vector< double > B; vector< double > V; vector< double > VMid; /* * Loop over cells. */ int i; int j; //~ bool success; int nCompt; int* array; unsigned int arraySize; for ( unsigned int cell = 0; cell < childArray.size(); cell++ ) { array = childArray[ cell ]; arraySize = childArraySize[ cell ]; nCompt = count( array, array + arraySize, -1 ); ////////////////////////////////////////// // Prepare local information on cell ////////////////////////////////////////// tree.clear(); tree.resize( nCompt ); Em.clear(); V.clear(); for ( i = 0; i < nCompt; i++ ) { tree[ i ].Ra = 15.0 + 3.0 * i; tree[ i ].Rm = 45.0 + 15.0 * i; tree[ i ].Cm = 500.0 + 200.0 * i * i; Em.push_back( -0.06 ); V.push_back( -0.06 + 0.01 * i ); } int count = -1; for ( unsigned int a = 0; a < arraySize; a++ ) if ( array[ a ] == -1 ) count++; else tree[ count ].children.push_back( array[ a ] ); ////////////////////////////////////////// // Create cell inside moose; setup solver. ////////////////////////////////////////// Id n = shell->doCreate( "Neutral", Id(), "n", 1 ); vector< Id > c( nCompt ); for ( i = 0; i < nCompt; i++ ) { ostringstream name; name << "c" << i; c[ i ] = shell->doCreate( "Compartment", n, name.str() , 1); Field< double >::set( c[ i ], "Ra", tree[ i ].Ra ); Field< double >::set( c[ i ], "Rm", tree[ i ].Rm ); Field< double >::set( c[ i ], "Cm", tree[ i ].Cm ); Field< double >::set( c[ i ], "Em", Em[ i ] ); Field< double >::set( c[ i ], "initVm", V[ i ] ); Field< double >::set( c[ i ], "Vm", V[ i ] ); } for ( i = 0; i < nCompt; i++ ) { vector< unsigned int >& child = tree[ i ].children; for ( j = 0; j < ( int )( child.size() ); j++ ) { ObjId mid = shell->doAddMsg( "Single", c[ i ], "axial", c[ child[ j ] ], "raxial" ); ASSERT( ! mid.bad(), "Creating test model" ); } } HP.setup( c[ 0 ], dt ); /* * Here we check if the cell was read in correctly by the solver. * This test only checks if all the created compartments were read in. * It doesn't check if they have been assigned hines' indices correctly. */ vector< Id >& hc = HP.compartmentId_; ASSERT( ( int )( hc.size() ) == nCompt, "Tree traversal" ); for ( i = 0; i < nCompt; i++ ) ASSERT( find( hc.begin(), hc.end(), c[ i ] ) != hc.end(), "Tree traversal" ); ////////////////////////////////////////// // Setup local matrix ////////////////////////////////////////// /* * First we need to ensure that the hines' indices for the local model * and those inside the solver match. If the numbering is different, * then the matrices will not agree. * * In the following, we find out the indices assigned by the solver, * and impose them on the local data structures. */ // Figure out new indices vector< unsigned int > permutation( nCompt ); for ( i = 0; i < nCompt; i++ ) { unsigned int newIndex = find( hc.begin(), hc.end(), c[ i ] ) - hc.begin(); permutation[ i ] = newIndex; } // Shuffle compartment properties according to new order permute< TreeNodeStruct >( tree, permutation ); permute< double >( Em, permutation ); permute< double >( V, permutation ); // Update indices of children for ( i = 0; i < nCompt; i++ ) { vector< unsigned int >& child = tree[ i ].children; for ( j = 0; j < ( int )( child.size() ); j++ ) child[ j ] = permutation[ child[ j ] ]; } // Create local reference matrix makeFullMatrix( tree, dt, matrix ); VMid.resize( nCompt ); B.resize( nCompt ); vector< vector< double > > matrixCopy; matrixCopy.assign( matrix.begin(), matrix.end() ); ////////////////////////////////////////// // Run comparisons ////////////////////////////////////////// double tolerance; /* * Compare initial matrices */ tolerance = 2.0; for ( i = 0; i < nCompt; ++i ) for ( j = 0; j < nCompt; ++j ) { ostringstream error; error << "Testing matrix construction:" << " Cell# " << cell + 1 << " A(" << i << ", " << j << ")"; ASSERT ( isClose< double >( HP.getA( i, j ), matrix[ i ][ j ], tolerance ), error.str() ); } /* * * Gaussian elimination * */ tolerance = 4.0; // ratio to machine epsilon for ( int pass = 0; pass < 2; pass++ ) { /* * First update terms in the equation. This involves setting up the B * in Ax = B, using the latest voltage values. Also, the coefficients * stored in A have to be restored to their original values, since * the matrix is modified at the end of every pass of gaussian * elimination. */ // Do so in the solver.. HP.updateMatrix(); // ..locally.. matrix.assign( matrixCopy.begin(), matrixCopy.end() ); for ( i = 0; i < nCompt; i++ ) B[ i ] = V[ i ] * tree[ i ].Cm / ( dt / 2.0 ) + Em[ i ] / tree[ i ].Rm; // ..and compare B. for ( i = 0; i < nCompt; ++i ) { ostringstream error; error << "Updating right-hand side values:" << " Pass " << pass << " Cell# " << cell + 1 << " B(" << i << ")"; ASSERT ( isClose< double >( HP.getB( i ), B[ i ], tolerance ), error.str() ); } /* * Forward elimination.. */ // ..in solver.. HP.forwardEliminate(); // ..and locally.. int k; for ( i = 0; i < nCompt - 1; i++ ) for ( j = i + 1; j < nCompt; j++ ) { double div = matrix[ j ][ i ] / matrix[ i ][ i ]; for ( k = 0; k < nCompt; k++ ) matrix[ j ][ k ] -= div * matrix[ i ][ k ]; B[ j ] -= div * B[ i ]; } // ..then compare A.. for ( i = 0; i < nCompt; ++i ) for ( j = 0; j < nCompt; ++j ) { ostringstream error; error << "Forward elimination:" << " Pass " << pass << " Cell# " << cell + 1 << " A(" << i << ", " << j << ")"; ASSERT ( isClose< double >( HP.getA( i, j ), matrix[ i ][ j ], tolerance ), error.str() ); } // ..and also B. for ( i = 0; i < nCompt; ++i ) { ostringstream error; error << "Forward elimination:" << " Pass " << pass << " Cell# " << cell + 1 << " B(" << i << ")"; ASSERT ( isClose< double >( HP.getB( i ), B[ i ], tolerance ), error.str() ); } /* * Backward substitution.. */ // ..in solver.. HP.backwardSubstitute(); // ..and full back-sub on local matrix equation.. for ( i = nCompt - 1; i >= 0; i-- ) { VMid[ i ] = B[ i ]; for ( j = nCompt - 1; j > i; j-- ) VMid[ i ] -= VMid[ j ] * matrix[ i ][ j ]; VMid[ i ] /= matrix[ i ][ i ]; V[ i ] = 2 * VMid[ i ] - V[ i ]; } // ..and then compare VMid. for ( i = nCompt - 1; i >= 0; i-- ) { ostringstream error; error << "Back substitution:" << " Pass " << pass << " Cell# " << cell + 1 << " VMid(" << i << ")"; ASSERT ( isClose< double >( HP.getVMid( i ), VMid[ i ], tolerance ), error.str() ); } for ( i = nCompt - 1; i >= 0; i-- ) { ostringstream error; error << "Back substitution:" << " Pass " << pass << " Cell# " << cell + 1 << " V(" << i << ")"; ASSERT ( isClose< double >( HP.getV( i ), V[ i ], tolerance ), error.str() ); } } // cleanup shell->doDelete( n ); } // TEST_END; }
void testCalcJunction() { Shell* s = reinterpret_cast< Shell* >( Id().eref().data() ); // Make a neuron with same-size dend and spine. PSD is tiny. // Put a, b, c in dend, b, c, d in spine, c, d, f in psd. No reacs. // See settling of all concs by diffusion, pairwise. Id model = s->doCreate( "Neutral", Id(), "model", 1 ); Id dend = s->doCreate( "Compartment", model, "dend", 1 ); Id neck = s->doCreate( "Compartment", model, "spine_neck", 1 ); Id head = s->doCreate( "Compartment", model, "spine_head", 1 ); Field< double >::set( dend, "x", 10e-6 ); Field< double >::set( dend, "diameter", 2e-6 ); Field< double >::set( dend, "length", 10e-6 ); Field< double >::set( neck, "x0", 9e-6 ); Field< double >::set( neck, "x", 9e-6 ); Field< double >::set( neck, "y", 1e-6 ); Field< double >::set( neck, "diameter", 0.5e-6 ); Field< double >::set( neck, "length", 1.0e-6 ); Field< double >::set( head, "x0", 9e-6 ); Field< double >::set( head, "x", 9e-6 ); Field< double >::set( head, "y0", 1e-6 ); Field< double >::set( head, "y", 11e-6 ); Field< double >::set( head, "diameter", 2e-6 ); Field< double >::set( head, "length", 10e-6 ); s->doAddMsg( "Single", ObjId( dend ), "raxial", ObjId( neck ), "axial"); s->doAddMsg( "Single", ObjId( neck ), "raxial", ObjId( head ), "axial"); Id nm = s->doCreate( "NeuroMesh", model, "nm", 1 ); Field< double >::set( nm, "diffLength", 10e-6 ); Field< bool >::set( nm, "separateSpines", true ); Id sm = s->doCreate( "SpineMesh", model, "sm", 1 ); Id pm = s->doCreate( "PsdMesh", model, "pm", 1 ); ObjId mid = s->doAddMsg( "Single", ObjId( nm ), "spineListOut", ObjId( sm ), "spineList" ); assert( !mid.bad() ); mid = s->doAddMsg( "Single", ObjId( nm ), "psdListOut", ObjId( pm ), "psdList" ); Field< Id >::set( nm, "cell", model ); vector< Id > pools( 9 ); static string names[] = {"a", "b", "c", "b", "c", "d", "c", "d", "e" }; static Id parents[] = {nm, nm, nm, sm, sm, sm, pm, pm, pm}; for ( unsigned int i = 0; i < 9; ++i ) { pools[i] = s->doCreate( "Pool", parents[i], names[i], 1 ); assert( pools[i] != Id() ); Field< double >::set( pools[i], "concInit", 1.0 + 1.0 * i ); Field< double >::set( pools[i], "diffConst", 1e-11 ); if ( i < 6 ) { double vol = Field< double >::get( pools[i], "volume" ); assert( doubleEq( vol, 10e-6 * 1e-12 * PI ) ); } } Id dendsolve = s->doCreate( "Dsolve", model, "dendsolve", 1 ); Id spinesolve = s->doCreate( "Dsolve", model, "spinesolve", 1 ); Id psdsolve = s->doCreate( "Dsolve", model, "psdsolve", 1 ); Field< Id >::set( dendsolve, "compartment", nm ); Field< Id >::set( spinesolve, "compartment", sm ); Field< Id >::set( psdsolve, "compartment", pm ); Field< string >::set( dendsolve, "path", "/model/nm/#" ); Field< string >::set( spinesolve, "path", "/model/sm/#" ); Field< string >::set( psdsolve, "path", "/model/pm/#" ); assert( Field< unsigned int >::get( dendsolve, "numAllVoxels" ) == 1 ); assert( Field< unsigned int >::get( spinesolve, "numAllVoxels" ) == 1 ); assert( Field< unsigned int >::get( psdsolve, "numAllVoxels" ) == 1 ); assert( Field< unsigned int >::get( dendsolve, "numPools" ) == 3 ); assert( Field< unsigned int >::get( spinesolve, "numPools" ) == 3 ); assert( Field< unsigned int >::get( psdsolve, "numPools" ) == 3 ); SetGet2< Id, Id >::set( dendsolve, "buildNeuroMeshJunctions", spinesolve, psdsolve ); s->doSetClock( 0, 0.01 ); s->doUseClock( "/model/#solve", "process", 0 ); s->doReinit(); s->doStart( 100 ); for ( unsigned int i = 0; i < 9; ++i ) { double c = Field< double >::get( pools[i], "conc" ); double n = Field< double >::get( pools[i], "n" ); double v = Field< double >::get( pools[i], "volume" ); cout << pools[i].path() << ": " << c << ", " << n << ", " << n / v << ", " << v << endl; } s->doDelete( model ); cout << "." << flush; }
void testCompartmentProcess() { Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() ); unsigned int size = 100; double Rm = 1.0; double Ra = 0.01; double Cm = 1.0; double dt = 0.01; double runtime = 10; double lambda = sqrt( Rm / Ra ); Id cid = shell->doCreate( "Compartment", Id(), "compt", size ); assert( Id::isValid(cid)); assert( cid.eref().element()->numData() == size ); bool ret = Field< double >::setRepeat( cid, "initVm", 0.0 ); assert( ret ); Field< double >::setRepeat( cid, "inject", 0 ); // Only apply current injection in first compartment Field< double >::set( ObjId( cid, 0 ), "inject", 1.0 ); Field< double >::setRepeat( cid, "Rm", Rm ); Field< double >::setRepeat( cid, "Ra", Ra ); Field< double >::setRepeat( cid, "Cm", Cm ); Field< double >::setRepeat( cid, "Em", 0 ); Field< double >::setRepeat( cid, "Vm", 0 ); // The diagonal message has a default stride of 1, so it connects // successive compartments. // Note that the src and dest elements here are identical, so we cannot // use a shared message. The messaging system will get confused about // direction to send data. So we split up the shared message that we // might have used, below, into two individual messages. // MsgId mid = shell->doAddMsg( "Diagonal", ObjId( cid ), "raxial", ObjId( cid ), "axial" ); ObjId mid = shell->doAddMsg( "Diagonal", ObjId( cid ), "axialOut", ObjId( cid ), "handleAxial" ); assert( !mid.bad()); // mid = shell->doAddMsg( "Diagonal", ObjId( cid ), "handleRaxial", ObjId( cid ), "raxialOut" ); mid = shell->doAddMsg( "Diagonal", ObjId( cid ), "raxialOut", ObjId( cid ), "handleRaxial" ); assert( !mid.bad() ); // ObjId managerId = Msg::getMsg( mid )->manager().objId(); // Make the raxial data go from high to lower index compartments. Field< int >::set( mid, "stride", -1 ); #ifdef DO_SPATIAL_TESTS shell->doSetClock( 0, dt ); shell->doSetClock( 1, dt ); // Ensure that the inter_compt msgs go between nodes once every dt. shell->doSetClock( 9, dt ); shell->doUseClock( "/compt", "init", 0 ); shell->doUseClock( "/compt", "process", 1 ); shell->doReinit(); shell->doStart( runtime ); double Vmax = Field< double >::get( ObjId( cid, 0 ), "Vm" ); double delta = 0.0; // We measure only the first 50 compartments as later we // run into end effects because it is not an infinite cable for ( unsigned int i = 0; i < size; i++ ) { double Vm = Field< double >::get( ObjId( cid, i ), "Vm" ); double x = Vmax * exp( - static_cast< double >( i ) / lambda ); delta += ( Vm - x ) * ( Vm - x ); // cout << i << " (x, Vm) = ( " << x << ", " << Vm << " )\n"; } assert( delta < 1.0e-5 ); #endif // DO_SPATIAL_TESTS shell->doDelete( cid ); cout << "." << flush; }
void testAssortedMsg() { Eref sheller = Id().eref(); Shell* shell = reinterpret_cast< Shell* >( sheller.data() ); ObjId pa = shell->doCreate( "Neutral", ObjId(), "pa", 1 ); unsigned int numData = 5; /////////////////////////////////////////////////////////// // Set up the objects. /////////////////////////////////////////////////////////// Id a1 = shell->doCreate( "Arith", pa, "a1", numData ); Id a2 = shell->doCreate( "Arith", pa, "a2", numData ); Id b1 = shell->doCreate( "Arith", pa, "b1", numData ); Id b2 = shell->doCreate( "Arith", pa, "b2", numData ); Id c1 = shell->doCreate( "Arith", pa, "c1", numData ); Id c2 = shell->doCreate( "Arith", pa, "c2", numData ); Id d1 = shell->doCreate( "Arith", pa, "d1", numData ); Id d2 = shell->doCreate( "Arith", pa, "d2", numData ); Id e1 = shell->doCreate( "Arith", pa, "e1", numData ); Id e2 = shell->doCreate( "Arith", pa, "e2", numData ); /////////////////////////////////////////////////////////// // Set up initial conditions /////////////////////////////////////////////////////////// bool ret = 0; vector< double > init; // 12345 for ( unsigned int i = 1; i < 6; ++i ) init.push_back( i ); ret = SetGet1< double >::setVec( a1, "arg1", init ); // 12345 assert( ret ); ret = SetGet1< double >::setVec( b1, "arg1", init ); // 12345 assert( ret ); ret = SetGet1< double >::setVec( c1, "arg1", init ); // 12345 assert( ret ); ret = SetGet1< double >::setVec( d1, "arg1", init ); // 12345 assert( ret ); ret = SetGet1< double >::setVec( e1, "arg1", init ); // 12345 assert( ret ); /////////////////////////////////////////////////////////// // Set up messaging /////////////////////////////////////////////////////////// // Should give 04000 ObjId m1 = shell->doAddMsg( "Single", ObjId( a1, 3 ), "output", ObjId( a2, 1 ), "arg1" ); assert( !m1.bad() ); // Should give 33333 ObjId m2 = shell->doAddMsg( "OneToAll", ObjId( b1, 2 ), "output", ObjId( b2, 0 ), "arg1" ); assert( !m2.bad() ); // Should give 12345 ObjId m3 = shell->doAddMsg( "OneToOne", ObjId( c1, 0 ), "output", ObjId( c2, 0 ), "arg1" ); assert( !m3.bad() ); // Should give 01234 ObjId m4 = shell->doAddMsg( "Diagonal", ObjId( d1, 0 ), "output", ObjId( d2, 0 ), "arg1" ); assert( !m4.bad() ); // Should give 54321 ObjId m5 = shell->doAddMsg( "Sparse", ObjId( e1, 0 ), "output", ObjId( e2, 0 ), "arg1" ); assert( !m5.bad() ); ret = SetGet3< unsigned int, unsigned int, unsigned int >::set( m5, "setEntry", 0, 4, 0 ); assert( ret ); ret = SetGet3< unsigned int, unsigned int, unsigned int >::set( m5, "setEntry", 1, 3, 0 ); assert( ret ); ret = SetGet3< unsigned int, unsigned int, unsigned int >::set( m5, "setEntry", 2, 2, 0 ); assert( ret ); ret = SetGet3< unsigned int, unsigned int, unsigned int >::set( m5, "setEntry", 3, 1, 0 ); assert( ret ); ret = SetGet3< unsigned int, unsigned int, unsigned int >::set( m5, "setEntry", 4, 0, 0 ); assert( ret ); assert( ret ); /////////////////////////////////////////////////////////// // Test traversal /////////////////////////////////////////////////////////// // Single ObjId f = Msg::getMsg( m1 )->findOtherEnd( ObjId( a1, 3 ) ); assert( f == ObjId( a2, 1 ) ); f = Msg::getMsg( m1 )->findOtherEnd( ObjId( a2, 1 ) ); assert( f == ObjId( a1, 3 ) ); f = Msg::getMsg( m1 )->findOtherEnd( ObjId( a1, 0 ) ); assert( f.bad() ); f = Msg::getMsg( m1 )->findOtherEnd( ObjId( a2, 0 ) ); assert( f.bad() ); f = Msg::getMsg( m1 )->findOtherEnd( ObjId( b2, 1 ) ); assert( f.bad() ); // OneToAll f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b1, 2 ) ); assert( f == ObjId( b2, 0 ) ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b2, 0 ) ); assert( f == ObjId( b1, 2 ) ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b2, 1 ) ); assert( f == ObjId( b1, 2 ) ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b2, 2 ) ); assert( f == ObjId( b1, 2 ) ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b2, 3 ) ); assert( f == ObjId( b1, 2 ) ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b2, 4 ) ); assert( f == ObjId( b1, 2 ) ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( b1, 0 ) ); assert( f.bad() ); f = Msg::getMsg( m2 )->findOtherEnd( ObjId( a2, 1 ) ); assert( f.bad() ); // OneToOne for ( unsigned int i = 0; i < 5; ++i ) { f = Msg::getMsg( m3 )->findOtherEnd( ObjId( c1, i ) ); assert( f == ObjId( c2, i ) ); f = Msg::getMsg( m3 )->findOtherEnd( ObjId( c2, i ) ); assert( f == ObjId( c1, i ) ); } f = Msg::getMsg( m3 )->findOtherEnd( ObjId( a2, 1 ) ); assert( f.bad() ); // Diagonal for ( unsigned int i = 0; i < 4; ++i ) { f = Msg::getMsg( m4 )->findOtherEnd( ObjId( d1, i ) ); assert( f == ObjId( d2, i + 1 ) ); f = Msg::getMsg( m4 )->findOtherEnd( ObjId( d2, i + 1 ) ); assert( f == ObjId( d1, i ) ); } f = Msg::getMsg( m4 )->findOtherEnd( ObjId( d1, 4 ) ); assert( f.bad() ); f = Msg::getMsg( m4 )->findOtherEnd( ObjId( d2, 0 ) ); assert( f.bad() ); f = Msg::getMsg( m4 )->findOtherEnd( ObjId( a2, 1 ) ); assert( f.bad() ); // Sparse for ( unsigned int i = 0; i < 5; ++i ) { f = Msg::getMsg( m5 )->findOtherEnd( ObjId( e1, i ) ); assert( f == ObjId( e2, 4 - i ) ); f = Msg::getMsg( m5 )->findOtherEnd( ObjId( e2, i ) ); assert( f == ObjId( e1, 4 - i ) ); } f = Msg::getMsg( m5 )->findOtherEnd( ObjId( a2, 1 ) ); assert( f.bad() ); cout << "." << flush; /////////////////////////////////////////////////////////// // Check lookup by funcId. /////////////////////////////////////////////////////////// const Finfo* aFinfo = Arith::initCinfo()->findFinfo( "arg1" ); FuncId afid = dynamic_cast< const DestFinfo* >( aFinfo )->getFid(); ObjId m = a2.element()->findCaller( afid ); assert ( m == m1 ); m = b2.element()->findCaller( afid ); assert ( m == m2 ); m = c2.element()->findCaller( afid ); assert ( m == m3 ); m = d2.element()->findCaller( afid ); assert ( m == m4 ); m = e2.element()->findCaller( afid ); assert ( m == m5 ); /////////////////////////////////////////////////////////// // Clean up. /////////////////////////////////////////////////////////// shell->doDelete( pa ); cout << "." << flush; }
void testHSolveUtils( ) { //TEST_BEGIN; Shell* shell = reinterpret_cast< Shell* >( Id().eref().data() ); bool success; Id n = shell->doCreate( "Neutral", Id(), "n", 1 ); /** * 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.) */ Id c[ 6 ]; c[ 0 ] = shell->doCreate( "Compartment", n, "c0", 1 ); c[ 1 ] = shell->doCreate( "Compartment", n, "c1", 1 ); c[ 2 ] = shell->doCreate( "Compartment", n, "c2", 1 ); c[ 3 ] = shell->doCreate( "Compartment", n, "c3", 1 ); c[ 4 ] = shell->doCreate( "Compartment", n, "c4", 1 ); c[ 5 ] = shell->doCreate( "Compartment", n, "c5", 1 ); ObjId mid; mid = shell->doAddMsg( "Single", c[ 0 ], "axial", c[ 1 ], "raxial" ); ASSERT( ! mid.bad(), "Linking compartments" ); mid = shell->doAddMsg( "Single", c[ 1 ], "axial", c[ 2 ], "raxial" ); ASSERT( ! mid.bad(), "Linking compartments" ); mid = shell->doAddMsg( "Single", c[ 1 ], "axial", c[ 3 ], "raxial" ); ASSERT( ! mid.bad(), "Linking compartments" ); mid = shell->doAddMsg( "Single", c[ 1 ], "axial", c[ 4 ], "raxial" ); ASSERT( ! mid.bad(), "Linking compartments" ); mid = shell->doAddMsg( "Single", c[ 1 ], "axial", c[ 5 ], "raxial" ); ASSERT( ! mid.bad(), "Linking compartments" ); vector< Id > found; unsigned int nFound; /* * Testing version 1 of HSolveUtils::adjacent. * It finds all neighbors of given compartment. */ // Neighbors of c0 nFound = HSolveUtils::adjacent( c[ 0 ], found ); ASSERT( nFound == found.size(), "Finding adjacent compartments" ); // c1 is adjacent ASSERT( nFound == 1, "Finding adjacent compartments" ); ASSERT( found[ 0 ] == c[ 1 ], "Finding adjacent compartments" ); // Neighbors of c1 found.clear(); nFound = HSolveUtils::adjacent( c[ 1 ], found ); ASSERT( nFound == 5, "Finding adjacent compartments" ); // c0 is adjacent success = find( found.begin(), found.end(), c[ 0 ] ) != 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 ] ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); } // Neighbors of c2 found.clear(); nFound = HSolveUtils::adjacent( c[ 2 ], found ); // c1 is adjacent ASSERT( nFound == 1, "Finding adjacent compartments" ); ASSERT( found[ 0 ] == c[ 1 ], "Finding adjacent compartments" ); /* * Testing version 2 of HSolveUtils::adjacent. * It finds all but one neighbors of given compartment. * The the second argument to 'adjacent' is the one that is excluded. */ // Neighbors of c1 (excluding c0) found.clear(); nFound = HSolveUtils::adjacent( c[ 1 ], c[ 0 ], 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 ] ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); } // Neighbors of c1 (excluding c2) found.clear(); nFound = HSolveUtils::adjacent( c[ 1 ], c[ 2 ], found ); ASSERT( nFound == 4, "Finding adjacent compartments" ); // c0 is adjacent success = find( found.begin(), found.end(), c[ 0 ] ) != 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 ] ) != found.end(); ASSERT( success, "Finding adjacent compartments" ); } // Neighbors of c2 (excluding c1) found.clear(); nFound = HSolveUtils::adjacent( c[ 2 ], c[ 1 ], found ); // None adjacent, if c1 is excluded ASSERT( nFound == 0, "Finding adjacent compartments" ); // Neighbors of c2 (excluding c3) found.clear(); nFound = HSolveUtils::adjacent( c[ 2 ], c[ 3 ], found ); // c1 is adjacent, while c3 is not even connected ASSERT( nFound == 1, "Finding adjacent compartments" ); ASSERT( found[ 0 ] == c[ 1 ], "Finding adjacent compartments" ); /* * Testing HSolveUtils::children. * It finds all compartments which are dests for the "axial" message. */ // Children of c0 found.clear(); nFound = HSolveUtils::children( c[ 0 ], found ); ASSERT( nFound == 1, "Finding child compartments" ); // c1 is a child ASSERT( found[ 0 ] == c[ 1 ], "Finding child compartments" ); // Children of c1 found.clear(); nFound = HSolveUtils::children( c[ 1 ], 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 ] ) != found.end(); ASSERT( success, "Finding child compartments" ); } // Children of c2 found.clear(); nFound = HSolveUtils::children( c[ 2 ], found ); // c2 has no children ASSERT( nFound == 0, "Finding child compartments" ); // Clean up shell->doDelete( n ); // TEST_END; }