std::vector<MOL_SPTR_VECT> EnumerateLibrary::next() { PRECONDITION(static_cast<bool>(*this), "No more enumerations"); const RGROUPS &reactantIndices = m_enumerator->next(); MOL_SPTR_VECT reactants(m_bbs.size()); for (size_t i = 0; i < m_bbs.size(); ++i) { reactants[i] = m_bbs[i][reactantIndices[i]]; } return m_rxn.runReactants(reactants); }
/** * Add a single reaction to the mechanism. This routine * must be called after init() and before finalize(). * This function branches on the types of reactions allowed * by the interfaceKinetics manager in order to install * the reaction correctly in the manager. * The manager allows the following reaction types * Elementary * Surface * Global * There is no difference between elementary and surface * reactions. */ void InterfaceKinetics::addReaction(const ReactionData& r) { /* * Install the rate coefficient for the current reaction * in the appropriate data structure. */ addElementaryReaction(r); /* * Add the reactants and products for m_ropnet;the current reaction * to the various stoichiometric coefficient arrays. */ installReagents(r); /* * Save the reaction and product groups, which are * part of the ReactionData class, in this class. * They aren't used for anything but reaction path * analysis. */ //installGroups(reactionNumber(), r.rgroups, r.pgroups); /* * Increase the internal number of reactions, m_ii, by one. * increase the size of m_perturb by one as well. */ incrementRxnCount(); m_rxneqn.push_back(r.equation); m_rxnPhaseIsReactant.resize(m_ii, 0); m_rxnPhaseIsProduct.resize(m_ii, 0); int np = nPhases(); int i = m_ii -1; m_rxnPhaseIsReactant[i] = new bool[np]; m_rxnPhaseIsProduct[i] = new bool[np]; for (int p = 0; p < np; p++) { m_rxnPhaseIsReactant[i][p] = false; m_rxnPhaseIsProduct[i][p] = false; } const vector_int& vr = reactants(i); for (int ik = 0; ik < (int) vr.size(); ik++) { int k = vr[ik]; int p = speciesPhaseIndex(k); m_rxnPhaseIsReactant[i][p] = true; } const vector_int& vp = products(i); for (int ik = 0; ik < (int) vp.size(); ik++) { int k = vp[ik]; int p = speciesPhaseIndex(k); m_rxnPhaseIsProduct[i][p] = true; } }
int main( int argc, char* argv[] ) { if ( argc != 2 ) { showUsage(); return 0; } // Start the rng. RandomGenerator rng( 41u ); UniformRandomSize sizeTypeRng( rng, boost::uniform_int< std::size_t >( 0, std::numeric_limits< std::size_t >::max() ) ); // Parse the input file. std::ifstream input( argv[1] ); std::string line; // The interaction database file. std::string xmlDatabaseFile; input >> xmlDatabaseFile; getline( input, line ); InteractionDatabase myDatabase( xmlDatabaseFile ); // Time and time step. double deltaTime, endTime, outputDeltaTime; input >> deltaTime; getline( input, line ); input >> endTime; getline( input, line ); // Output info. input >> outputDeltaTime; getline( input, line ); std::size_t numberOfOutputBins; input >> numberOfOutputBins; getline( input, line ); // Volume of the domain. double cellVolumeCubicMeters; input >> cellVolumeCubicMeters; getline( input, line ); // Particle species, counts, and temperatures. std::multimap< std::string, ParticleInputSpec > particleInitialConditions; while ( true ) { std::string speciesName; std::size_t particleCount; double particleTemperature; Vec3 commonVelocity; input >> speciesName >> particleCount >> particleTemperature >> commonVelocity; if ( ! input.good() ) { break; } else { getline( input, line ); } ParticleInputSpec inputSpec = { particleCount, particleTemperature, commonVelocity }; particleInitialConditions.insert( std::make_pair( speciesName, inputSpec ) ); } input.close(); // Add all species types to the database. typedef std::multimap< std::string, ParticleInputSpec >::const_iterator ConstSpecIterator; for ( ConstSpecIterator speciesIterator = particleInitialConditions.begin(); speciesIterator != particleInitialConditions.end(); speciesIterator = particleInitialConditions.upper_bound( speciesIterator->first ) ) { myDatabase.addParticleType( speciesIterator->first ); } // Throw away all interactions except elastic reactions. // myDatabase.filter = boost::make_shared< chimp::interaction::filter::Elastic >(); // Finalize the database and do housekeeping. myDatabase.initBinaryInteractions(); myDatabase.xmlDb.close(); // Now make up some particles. We use the same indexing as the particle database to ease bookkeeping. typedef std::vector< Particle > AllParticlesOfOneSpecies; std::vector< AllParticlesOfOneSpecies > speciesSets( myDatabase.getProps().size() ); for ( int i = 0; i < myDatabase.getProps().size(); ++i ) { // Find the pertinent particle specs. std::string speciesName = myDatabase[i].name::value; for ( ConstSpecIterator speciesIterator = particleInitialConditions.lower_bound( speciesName ); speciesIterator != particleInitialConditions.upper_bound( speciesName ); ++speciesIterator ) { const ParticleInputSpec& spec = speciesIterator->second; // Give the particles some random velocities plus the common velocity. for ( std::size_t particleIndex = 0; particleIndex < spec.count; ++particleIndex ) { Particle particle; particle.velocity = randomVelocityFromMaxwellian( rng, spec.temperatureInKelvin, myDatabase[i].mass::value ); particle.velocity += spec.driftVelocity; speciesSets[i].push_back( particle ); } } } // Write some info for the reaction set. std::cout << "BEGIN INTERACTION TABLE" << std::endl; BOOST_FOREACH( const InteractionDatabase::Set& reactionBranches, myDatabase.getInteractions() ) { if ( reactionBranches.rhs.size() == 0 ) continue; std::cout << " Reactions of " << myDatabase[ reactionBranches.lhs.A.species ].name::value << " with " << myDatabase[ reactionBranches.lhs.B.species ].name::value << std::endl; BOOST_FOREACH( const InteractionDatabase::Set::Equation& eq, reactionBranches.rhs ) { eq.print( std::cout << " ", myDatabase ) << std::endl; } } std::cout << "END INTERACTION TABLE" << std::endl; // Loop over time steps. const double beginTime = 0.; for ( double time = beginTime; time < endTime; time += deltaTime ) { // Update particle positions, max speeds, and temperatures. std::vector< double > maxSpeedMetersPerSecond; std::vector< double > speciesTemperatures; std::size_t collisionCount = 0; std::size_t particleCount = 0; for ( int speciesIndex = 0; speciesIndex < speciesSets.size(); ++speciesIndex ) { maxSpeedMetersPerSecond.push_back( 0. ); speciesTemperatures.push_back( 0. ); BOOST_FOREACH( Particle& particle, speciesSets[ speciesIndex ] ) { // v = v + E * dt; // x = x + v * dt; double particleSpeedSquared = magnitudeSquared( particle.velocity ); maxSpeedMetersPerSecond.back() = std::max( maxSpeedMetersPerSecond.back(), sqrt( particleSpeedSquared ) ); speciesTemperatures.back() += particleSpeedSquared; ++particleCount; } speciesTemperatures.back() *= 0.5 * myDatabase[ speciesIndex ].mass::value; // kinetic energy speciesTemperatures.back() /= 1.5 * physical::constant::si::K_B * speciesSets[ speciesIndex ].size(); } if ( time == beginTime ) { printConsoleData( myDatabase, speciesTemperatures, 0.0, 0, particleCount, true ); } // Collide a few particles. This is done by looping over all reactions, choosing a few pairs of // the pertinent 2 species, and doing a null-collision algorithm on these pairs. BOOST_FOREACH( const InteractionDatabase::Set& reactionBranches, myDatabase.getInteractions() ) { if ( reactionBranches.rhs.size() == 0 ) continue; std::vector< std::size_t > particlesPerSpecies; std::vector< int > reactantIndices; reactantIndices.push_back( reactionBranches.lhs.A.species ); reactantIndices.push_back( reactionBranches.lhs.B.species ); std::size_t numberOfCollisions = 1; BOOST_FOREACH( const int& reactantIndex, reactantIndices ) { particlesPerSpecies.push_back( speciesSets[ reactantIndex ].size() ); numberOfCollisions *= particlesPerSpecies.back(); } // Round the number of collisions based on the remainder using MC method. double maxRelativeSpeed = std::accumulate( maxSpeedMetersPerSecond.begin(), maxSpeedMetersPerSecond.end(), 0. ); double maxSigmaSpeedProduct = reactionBranches.findMaxSigmaVProduct( maxRelativeSpeed ); double fractionalCollisions = numberOfCollisions * maxSigmaSpeedProduct * deltaTime / cellVolumeCubicMeters; numberOfCollisions = static_cast< std::size_t >( std::floor( fractionalCollisions ) ); double partialCollision = fractionalCollisions - numberOfCollisions; UniformRandomDouble remainderSelector( rng, boost::uniform_real<>( 0., 1. ) ); if ( remainderSelector() < partialCollision ) { ++numberOfCollisions; } // Setup some dummy vectors to hold arguments. std::vector< InteractionDatabase::options::Particle > reactants( 2 ); std::vector< const InteractionDatabase::options::Particle* > reactantPointers( 2 ); for ( int i = 0; i < 2; ++i ) { reactantPointers[i] = &reactants[i]; } // Loop over all of the chosen collision pairs. for ( std::size_t collisionPair = 0; collisionPair < numberOfCollisions; ++collisionPair ) { // Choose the particles randomly, making sure we don't pick the same particle twice if this // is a like-pair collision. boost::array< std::size_t, 2 > particleIndex; particleIndex[0] = sizeTypeRng() % particlesPerSpecies[0]; particleIndex[1] = sizeTypeRng() % particlesPerSpecies[1]; if ( reactantIndices[0] == reactantIndices[1] ) { while ( particleIndex[1] == particleIndex[0] ) { particleIndex[1] = sizeTypeRng() % particlesPerSpecies[1]; } } // Copy over the velocities. for ( int i = 0; i < 2; ++i ) { for ( int j = 0; j < 3; ++j ) reactants[i].v[j] = speciesSets[ reactantIndices[i] ][ particleIndex[i] ].velocity[j]; } double relativeSpeed = magnitude( reactants[0].v - reactants[1].v ); if ( relativeSpeed == 0.0 ) { continue; } // Find which branch to take using null collision method. std::pair< int, double > path = reactionBranches.calculateOutPath( maxSigmaSpeedProduct, relativeSpeed ); // Skip it if there is no collision. if ( path.first < 0 ) { continue; } const InteractionDatabase::Set::Equation& selectedPath = reactionBranches.rhs[ path.first ]; InteractionDatabase::Interaction::ParticleParam defaultParam; defaultParam.is_set = false; // because it doesn't have a default constructor yet. std::vector< InteractionDatabase::Interaction::ParticleParam > products( 5, defaultParam ); selectedPath.interaction->interact( reactantPointers, products ); ++collisionCount; // For elastic collisions, we just copy the velocities of the products. for ( int i = 0; i < 2; ++i ) { std::vector< Particle >& species = speciesSets[ reactantIndices[i] ]; if ( products[i].is_set ) { // The original reactant was modified, but was not consumed. for ( int j = 0; j < 3; ++j ) { species[ particleIndex[i] ].velocity[j] = products[i].particle.v[j]; } } else { // The reactant was consumed. Remove it. species.erase( species.begin() + particleIndex[i] ); } } // Add the new particles if there were any created. for ( int i = 2; i < 5; ++i ) { if ( products[i].is_set ) { Particle newParticle; for ( int j = 0; j < 3; ++j ) { newParticle.velocity[j] = products[i].particle.v[j]; } speciesSets[ selectedPath.products[i-2].species ].push_back( newParticle ); } } } // collisionPair } // interaction