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 testHinesMatrix() { return; //~ cout << "\nTesting HinesMatrix" << flush; vector< int* > childArray; vector< unsigned int > childArraySize; /** * We test if the Hines' matrix is correctly setup 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 //////////////////////////////////////////////////////////////////////////// HinesMatrix H; vector< TreeNodeStruct > tree; double dt = 1.0; /* * This is the full reference matrix which will be compared to its sparse * implementation. */ vector< vector< double > > matrix; double epsilon = 1e-17; unsigned int i; unsigned int j; unsigned 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 cell tree.clear(); tree.resize( nCompt ); 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; } int count = -1; for ( unsigned int a = 0; a < arraySize; a++ ) if ( array[ a ] == -1 ) count++; else tree[ count ].children.push_back( array[ a ] ); // Prepare local matrix makeFullMatrix( tree, dt, matrix ); // Prepare sparse matrix H.setup( tree, dt ); // Compare matrices cout << "Testing Hines Matrix" << endl; cout << "Cell number " << cell << endl; for ( i = 0; i < nCompt; ++i ) { for ( j = 0; j < nCompt; ++j ) { ostringstream error; error << "Testing Hines' Matrix: Cell# " << cell + 1 << ", entry (" << i << ", " << j << ")"; ASSERT( fabs( matrix[ i ][ j ] - H.getA( i, j ) ) < epsilon, error.str() ); cout << matrix[i][j] << " "; } cout << endl; } } cout << "."; }