Ejemplo n.º 1
0
/**
 * Version that assumes all voxels are in contact and able to diffuse
 * with matching voxels on other mesh
 */
void CubeMesh::matchAllEntries( const CubeMesh* other,
	   vector< VoxelJunction >& ret ) const
{
	ret.clear();
	unsigned int min = m2s_.size();
	if ( min > other->m2s_.size() )
		min = other->m2s_.size();
	ret.resize( min );
	for ( unsigned int i = 0; i < min; ++i ) {
		ret[i] = VoxelJunction( i, i );
	}
}
Ejemplo n.º 2
0
void CylBase::matchCubeMeshEntries( const ChemCompt* compt,
	const CylBase& parent,
	unsigned int startIndex,
	double granularity,
	vector< VoxelJunction >& ret, 
	bool useCylinderCurve, bool useCylinderCap ) const
{
	const CubeMesh* other = dynamic_cast< const CubeMesh* >( compt );
	assert( other );
	const double EPSILON = 1e-18;
	Vec a( parent.x_ - x_, parent.y_ - y_, parent.z_ - z_ );
	Vec u;
	Vec v;
	a.orthogonalAxes( u, v );

	double h = selectGridSize( other->getDx(), parent.dia_/2, granularity );
	double lambda = length_ / numDivs_;

	unsigned int num = floor( 0.1 + lambda / h );
	// March along axis of cylinder.
	// q is the location of the point along axis.
	double rSlope = ( dia_ - parent.dia_ ) * 0.5 / length_;
	for ( unsigned int i = 0; i < numDivs_; ++i ) {
		vector< double >area( other->getNumEntries(), 0.0 );
		if ( useCylinderCurve ) {
			for ( unsigned int j = 0; j < num; ++j ) {
				unsigned int m = i * num + j;
				double frac = ( m * h + h/2.0 ) / length_;
				double q0 = x_ + a.a0() * frac;
				double q1 = y_ + a.a1() * frac;
				double q2 = z_ + a.a2() * frac;
				// get radius of cylinder at this point.
				double r = dia_/2.0;
				if ( !isCylinder_ ) // Use the more complicated conic value
				r = parent.dia_/2.0 + frac * rSlope;
				fillPointsOnCircle( u, v, Vec( q0, q1, q2 ),
							h, r, area, other );
			}
		}
		if ( useCylinderCap && i == numDivs_ - 1 ) {
			fillPointsOnDisc( u, v, Vec( x_, y_, z_ ), 
							h, dia_/2.0, area, other );
		}
		// Go through all cubeMesh entries and compute diffusion 
		// cross-section. Assume this is through a membrane, so the 
		// only factor relevant is area. Not the distance.
		for ( unsigned int k = 0; k < area.size(); ++k ) {
			if ( area[k] > EPSILON ) {
				ret.push_back( VoxelJunction( i + startIndex, k, area[k] ));
			}
		}
	}
}
Ejemplo n.º 3
0
void CylMesh::matchCubeMeshEntries( const CubeMesh* other,
vector< VoxelJunction >& ret ) const
{
	const double EPSILON = 1e-18;
	Vec a( x1_ - x0_, y1_ - y0_, z1_ - z0_ );
	Vec u;
	Vec v;
	a.orthogonalAxes( u, v );

	double h = selectGridVolume( other->getDx() );

	unsigned int num = floor( 0.1 + diffLength_ / h );
	// March along axis of cylinder.
	// q is the location of the point along axis.
	for ( unsigned int i = 0; i < numEntries_; ++i ) {
		vector< double >area( other->getNumEntries(), 0.0 );
		for ( unsigned int j = 0; j < num; ++j ) {
			unsigned int m = i * num + j;
			double frac = ( m * h + h/2.0 ) / totLen_;
			double q0 = x0_ + a.a0() * frac;
			double q1 = y0_ + a.a1() * frac;
			double q2 = z0_ + a.a2() * frac;
			// get radius of cylinder at this point.
			double r = r0_ + ( m * h + h / 2.0 ) * rSlope_;
			fillPointsOnCircle( u, v, Vec( q0, q1, q2 ),
						h, r, area, other );
			}
		// Go through all cubeMesh entries and compute diffusion 
		// cross-section. Assume this is through a membrane, so the 
		// only factor relevant is area. Not the distance.
		for ( unsigned int k = 0; k < area.size(); ++k ) {
			if ( area[k] > EPSILON ) {
				ret.push_back( VoxelJunction( i, k, area[k] ) );
			}
		}
	}
}
Ejemplo n.º 4
0
/**
 * extendStencil adds voxels to the current stencil m_, to build up a 
 * monolithic stencil that also handles the entries just past all the 
 * boundaries.
 * This function may be called many times to deal with the addition of
 * multiple junctions. Before the first of these calls, the m_ matrix
 * should be set to the coreStencil_.
 */
void MeshCompt::extendStencil( 
	const ChemCompt* other, const vector< VoxelJunction >& vj ) 
{
	// Maps from remote meshIndex (in vj) to local index of proxy voxel.
	map< unsigned int, unsigned int > meshMap;
	map< unsigned int, unsigned int >::iterator mmi;
	
	// Maps from local index of proxy voxel back to remote meshIndex.
	vector< unsigned int > meshBackMap;


	unsigned int coreSize = coreStencil_.nRows();
	unsigned int oldSize = m_.nRows();
	unsigned int newSize = oldSize;

	/// Organizes vj by voxel, that is, by row.
	vector< vector< VoxelJunction > > vvj( coreSize );

	for ( vector< VoxelJunction >::const_iterator 
					i = vj.begin(); i != vj.end(); ++i ) {
		mmi = meshMap.find( i->second );
		if ( mmi == meshMap.end() ) {
			assert( i->first < coreSize );
			meshBackMap.push_back( i->second );
			meshMap[i->second] = newSize++;
			vvj[i->first].push_back( *i );
		}
	}
	vector< vector< VoxelJunction > > vvjCol( newSize );
	SparseMatrix< double > oldM = m_;
	m_.clear();
	m_.setSize( newSize, newSize );
	for ( unsigned int i = 0; i < newSize; ++i ) {
		vector< VoxelJunction > temp;
		if ( i < oldSize ) { // Copy over old matrix.
			const double* entry;
			const unsigned int* colIndex;
			unsigned int num = oldM.getRow( i, &entry, &colIndex );
			temp.resize( num );
			for ( unsigned int j = 0; j < num; ++j ) {
				temp[j].first = colIndex[j];
				temp[j].diffScale = entry[j];
			}
		}
		if ( i < coreSize ) { // Set up diffusion into proxy voxels.
			for ( vector< VoxelJunction >::const_iterator
				j = vvj[i].begin(); j != vvj[i].end(); ++j )
			{
				unsigned int row = j->first;
				assert( row == i );
				unsigned int col = meshMap[j->second];
				assert( col >= oldSize );
				temp.push_back( 
						VoxelJunction( col, EMPTY, j->diffScale ) );
				vvjCol[col].push_back(
						VoxelJunction( row, EMPTY, j->diffScale ) );
			}
		}
		if ( i >= oldSize ) { // Set up diffusion from proxy to old voxels
			for ( vector< VoxelJunction >::const_iterator
				j = vvjCol[i].begin(); j != vvjCol[i].end(); ++j )
			{
				temp.push_back( *j );
			}
		}
		// Now we've filled in all the VoxelJunctions for the new row.
		sort( temp.begin(), temp.end() );
		vector< double > e( temp.size() );
		vector< unsigned int > c( temp.size() );
		for ( unsigned int j = 0; j < temp.size(); ++j ) {
			e[j] = temp[j].diffScale;
			c[j] = temp[j].first;
		}
		m_.addRow( i, e, c );
	}

	// Fill in the volumes of the external mesh entries
	for ( vector< unsigned int>::const_iterator  
			i = meshBackMap.begin(); i != meshBackMap.end(); ++i ) {
		extendedMeshEntryVolume_.push_back( other->getMeshEntryVolume( *i ) );
	}
}
Ejemplo n.º 5
0
/**
 * checkAbut checks the intersect vector for the current position 
 * ix, iy, iz, to determine how many diffusion terms to extract. It
 * then puts each of the extracted terms into the ret vector. There is
 * a minor efficiency for one and two diffusion terms as they are
 * encoded within the intersect vector. Higher-order surface alignments
 * require an in-line scan of neighboring voxels.
 * In all casesl the function inserts a flag indicating surface direction
 * into the diffScale
 * field of the VoxelJunction. 0 = x; 1 = y; 2 = z.
 */
void checkAbut( 
		const vector< PII >& intersect, 
		unsigned int ix, unsigned int iy, unsigned int iz,
		unsigned int nx, unsigned int ny, unsigned int nz,
		unsigned int meshIndex,
		vector< VoxelJunction >& ret 
   	)
{
	unsigned int index = ( iz * ny + iy ) * nx + ix;
	unsigned int localFlag = intersect[index].second;

	if ( localFlag == CubeMesh::EMPTY || localFlag == CubeMesh::SURFACE )
			return; // Nothing to put into the ret vector
	if ( localFlag == CubeMesh::ABUTX ) {
		ret.push_back( 
				VoxelJunction( intersect[index].first, meshIndex, 0 ));
	} else if ( localFlag == CubeMesh::ABUTY ) {
		ret.push_back( 
				VoxelJunction( intersect[index].first, meshIndex, 1 ));
	} else if ( localFlag == CubeMesh::ABUTZ ) {
		ret.push_back( 
				VoxelJunction( intersect[index].first, meshIndex, 2 ));
	} else if ( localFlag == CubeMesh::MULTI ) { // go through all 6 cases.
		if ( ix > 0 ) {
			index = ( iz * ny + iy ) * nx + ix - 1;
			if ( intersect[index].second == CubeMesh::SURFACE )
				ret.push_back( 
					VoxelJunction( intersect[index].first, meshIndex, 0 ));
		}
		if ( ix + 1 < nx ) {
			index = ( iz * ny + iy ) * nx + ix + 1;
			if ( intersect[index].second == CubeMesh::SURFACE )
				ret.push_back( 
					VoxelJunction( intersect[index].first, meshIndex, 0 ));
		}
		if ( iy > 0 ) {
			index = ( iz * ny + iy -1 ) * nx + ix;
			if ( intersect[index].second == CubeMesh::SURFACE )
				ret.push_back( 
					VoxelJunction( intersect[index].first, meshIndex, 1 ));
		}
		if ( iy + 1 < ny ) {
			index = ( iz * ny + iy + 1 ) * nx + ix;
			if ( intersect[index].second == CubeMesh::SURFACE )
				ret.push_back( 
					VoxelJunction( intersect[index].first, meshIndex, 1 ));
		}
		if ( iz > 0 ) {
			index = ( (iz-1) * ny + iy ) * nx + ix;
			if ( intersect[index].second == CubeMesh::SURFACE )
				ret.push_back( 
					VoxelJunction( intersect[index].first, meshIndex, 2 ));
		}
		if ( iz + 1 < nz ) {
			index = ( (iz+1) * ny + iy ) * nx + ix;
			if ( intersect[index].second == CubeMesh::SURFACE )
				ret.push_back( 
					VoxelJunction( intersect[index].first, meshIndex, 2 ));
		}
	}
}
Ejemplo n.º 6
0
// Look for end-to-end diffusion, not sideways for now.
// Very straightforward but tedious because of the different permutations.
// Could readily add cylinder side to other end.
void CylMesh::matchCylMeshEntries( const CylMesh* other,
vector< VoxelJunction >& ret ) const
{
	const double EPSILON = 1e-3;
	ret.clear();
	// Should really estimate the distance from the centre of the smaller 
	// cylinder cap disk to the plane of the larger disk, provided it is
	// within the radius of the disk. The subsequent calculations are the
	// same though.
	double dr1 = 
			distance(x0_ - other->x0_, y0_ - other->y0_, z0_ - other->z0_ );
	double dr2 = 
			distance(x1_ - other->x1_, y1_ - other->y1_, z1_ - other->z1_ );
	double dr3 = 
			distance(x1_ - other->x0_, y1_ - other->y0_, z1_ - other->z0_ );
	double dr4 = 
			distance(x0_ - other->x1_, y0_ - other->y1_, z0_ - other->z1_ );

	if ( dr1 <= dr2 && dr1 <= dr3 && dr1 <= dr4 ) {
		if ( ( dr1/totLen_ < EPSILON && dr1/other->totLen_ < EPSILON ) ) {
			double xda;
			if ( r0_ < other->r0_ )
				xda = 2 * r0_ * r0_ * PI / ( diffLength_ + other->diffLength_ );
			else 
				xda = 2 * other->r0_ * other->r0_ * PI / 
						( diffLength_ + other->diffLength_ );
			ret.push_back( VoxelJunction( 0, 0, xda ) );
		}
	} else if ( dr2 <= dr3 && dr2 <= dr4 ) {
		if ( ( dr2/totLen_ < EPSILON && dr2/other->totLen_ < EPSILON ) ) {
			double xda;
			if ( r1_ < other->r1_ )
				xda = 2 * r1_ * r1_ * PI / ( diffLength_ + other->diffLength_ );
			else 
				xda = 2 * other->r1_ * other->r1_ * PI / 
						( diffLength_ + other->diffLength_ );
			ret.push_back( VoxelJunction( numEntries_ - 1, 
						other->numEntries_ - 1, xda ) );
		}
	} else if ( dr3 <= dr4 ) {
		if ( ( dr3/totLen_ < EPSILON && dr3/other->totLen_ < EPSILON ) ) {
			double xda;
			if ( r1_ < other->r0_ )
				xda = 2 * r1_ * r1_ * PI / ( diffLength_ + other->diffLength_ );
			else 
				xda = 2 * other->r0_ * other->r0_ * PI / 
						( diffLength_ + other->diffLength_ );
			ret.push_back( VoxelJunction( numEntries_ - 1, 0, xda ) );
		}
	} else {
		if ( ( dr4/totLen_ < EPSILON && dr4/other->totLen_ < EPSILON ) ) {
			double xda;
			if ( r0_ < other->r1_ )
				xda = 2 * r0_ * r0_ * PI / ( diffLength_ + other->diffLength_ );
			else 
				xda = 2 * other->r1_ * other->r1_ * PI / 
						( diffLength_ + other->diffLength_ );
			ret.push_back( VoxelJunction( 0, other->numEntries_ - 1, xda ));
		}
	}
}