![]() |
|
|||
File indexing completed on 2025-04-17 08:10:30
0001 // 0002 // ******************************************************************** 0003 // * License and Disclaimer * 0004 // * * 0005 // * The Geant4 software is copyright of the Copyright Holders of * 0006 // * the Geant4 Collaboration. It is provided under the terms and * 0007 // * conditions of the Geant4 Software License, included in the file * 0008 // * LICENSE and available at http://cern.ch/geant4/license . These * 0009 // * include a list of copyright holders. * 0010 // * * 0011 // * Neither the authors of this software system, nor their employing * 0012 // * institutes,nor the agencies providing financial support for this * 0013 // * work make any representation or warranty, express or implied, * 0014 // * regarding this software system or assume any liability for its * 0015 // * use. Please see the license in the file LICENSE and URL above * 0016 // * for the full disclaimer and the limitation of liability. * 0017 // * * 0018 // * This code implementation is the result of the scientific and * 0019 // * technical work of the GEANT4 collaboration. * 0020 // * By using, copying, modifying or distributing the software (or * 0021 // * any work based on the software) you agree to acknowledge its * 0022 // * use in resulting scientific publications, and indicate your * 0023 // * acceptance of all terms of the Geant4 Software license. * 0024 // ******************************************************************** 0025 // 0026 // 0027 /// \file HadNucIneEvents.cc 0028 /// \brief Main program, 0029 /// hadronic/FlukaCern/ProcessLevel/FinalState example. 0030 // 0031 // Author: A. Ribbon, 8 November 2020 0032 // Modified: G. Hugo, 8 December 2022 0033 // 0034 //------------------------------------------------------------------------ 0035 // 0036 // HadNucIneEvents 0037 // 0038 /// This program is an adaptation of Hadr09 example. 0039 /// It offers all Hadr09 features, and adds the possibility of 0040 /// accessing hadron-nucleus inelastic interactions final states from FLUKA. 0041 /// 0042 /// With respect to the Hadr09 example, 0043 /// the program also adds the possibility of plotting the final state: 0044 /// all encountered secondaries spectra are automatically plotted, 0045 /// as well as the residual nuclei distributions. 0046 /// All plots (created via the G4 analysis manager) can be dumped 0047 /// to any of the usually supported formats (e.g. ROOT format), 0048 /// but also in a Flair-compatible format. 0049 /// 0050 /// The final states (i.e. secondary particles) produced by 0051 /// hadron-nuclear inelastic collisions are handled by HadronicGenerator. 0052 /// 0053 /// The use of the class Hadronic Generator is very simple: 0054 /// the constructor needs to be invoked only once - specifying the name 0055 /// of the "physics case" to consider ("CFLUKAHI" will be 0056 /// considered as default if the name is not specified) - and then one 0057 /// method needs to be called at each collision, specifying the type of 0058 /// collision (hadron, energy, direction, material) to be simulated. 0059 /// The class HadronicGenerator is expected to work also in a 0060 /// multi-threaded environment with "external" threads (i.e. threads 0061 /// that are not necessarily managed by Geant4 run-manager): 0062 /// each thread should have its own instance of the class. 0063 /// 0064 /// See the string "***LOOKHERE***" below for the setting of parameters 0065 /// of this example: the "physics case", the set of possibilities from 0066 /// which to sample the projectile 0067 /// a list of hadrons is possible from which to sample at each collision), 0068 /// the kinetic energy of the projectile (which can be sampled within 0069 /// an interval), whether the direction of the projectile is fixed or 0070 /// sampled at each collision, the target material (a list of materials 0071 /// is possible, from which the target material can be sampled at each 0072 /// collision, and then from this target material, the target nucleus 0073 /// will be chosen randomly by Geant4 itself), and whether to print out 0074 /// some information or not and how frequently. 0075 /// Once a well-defined type of hadron-nucleus 0076 /// inelastic collision has been chosen, the method 0077 /// HadronicGenerator::GenerateInteraction 0078 /// returns the secondaries produced by that interaction (in the form 0079 /// of a G4VParticleChange object). 0080 /// 0081 /// Here by default, an already well-defined type of hadron-nucleus 0082 /// inelastic collision is selected 0083 /// (specific hadron, at a given kinetic energy and direction, 0084 /// on a specific material). 0085 /// The initial random seed is not set randomly, 0086 /// so that results are reproducible from one simulation to the next. 0087 /// 0088 /// Use: build/HadNucIneEvents 0089 // 0090 //------------------------------------------------------------------------ 0091 0092 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 0093 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 0094 0095 #include "CLHEP/Random/Randomize.h" 0096 #include "CLHEP/Random/Ranlux64Engine.h" 0097 #include "FinalStateHistoManager.hh" 0098 #include "HadronicGenerator.hh" 0099 0100 #include "G4GenericIon.hh" 0101 #include "G4IonTable.hh" 0102 #include "G4Material.hh" 0103 #include "G4NistManager.hh" 0104 #include "G4ParticleTable.hh" 0105 #include "G4PhysicalConstants.hh" 0106 #include "G4ProcessManager.hh" 0107 #include "G4SystemOfUnits.hh" 0108 #include "G4UnitsTable.hh" 0109 #include "G4VParticleChange.hh" 0110 #include "G4ios.hh" 0111 #include "globals.hh" 0112 0113 #include <chrono> 0114 #include <iomanip> 0115 0116 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo...... 0117 0118 G4int main(G4int argc, char** argv) 0119 { 0120 G4cout << "=== Test of the HadronicGenerator ===" << G4endl; 0121 0122 // See the HadronicGenerator class for the possibilities and meaning of the "physics cases". 0123 // ( In short, it is the name of the Geant4 hadronic model used for the simulation of 0124 // the collision, with the possibility of having a transition between two models in 0125 // a given energy interval, as in physics lists. ) 0126 0127 //***LOOKHERE*** PHYSICS CASE 0128 G4String namePhysics = "CFLUKAHI"; 0129 // const G4String namePhysics = "FTFP_BERT"; 0130 // const G4String namePhysics = "FTFP_BERT_ATL"; 0131 // const G4String namePhysics = "QGSP_BERT"; 0132 // const G4String namePhysics = "QGSP_BIC"; 0133 // const G4String namePhysics = "FTFP_INCLXX"; 0134 // const G4String namePhysics = "FTFP"; 0135 // const G4String namePhysics = "QGSP"; 0136 // const G4String namePhysics = "BERT"; 0137 // const G4String namePhysics = "BIC"; 0138 // const G4String namePhysics = "IonBIC"; 0139 // const G4String namePhysics = "INCL"; 0140 0141 // The kinetic energy of the projectile will be sampled randomly, with flat probability 0142 // in the interval [minEnergy, maxEnergy]. 0143 G4double minEnergy = 7. * CLHEP::TeV; //***LOOKHERE*** HADRON PROJECTILE MIN Ekin 0144 G4double maxEnergy = 7. * CLHEP::TeV; //***LOOKHERE*** HADRON PROJECTILE MAX Ekin 0145 0146 G4int numCollisions = 100000; //***LOOKHERE*** NUMBER OF COLLISIONS 0147 // const G4int numCollisions = 100; // DEBUG 0148 0149 // IMPORTANT - TESTING ONLY: 0150 // OVERWRITES DEFAULT PHYSICS CASE AND NUMBER OF EVENTS 0151 std::vector<G4String> args(argv, argv + argc); 0152 if (args.size() == 2 && args[1] == "--test") { 0153 namePhysics = G4String("FTFP_BERT"); 0154 numCollisions = 10; 0155 } 0156 0157 // Enable or disable the print out of this program: if enabled, the number of secondaries 0158 // produced in each collisions is printed out; moreover, once every "printingGap" 0159 // collisions, the list of secondaries is printed out. 0160 const G4bool isPrintingEnabled = true; //***LOOKHERE*** PRINT OUT ON/OFF 0161 const G4int printingGap = 100; //***LOOKHERE*** GAP IN PRINTING 0162 0163 // Vector of Geant4 names of hadron projectiles: one of this will be sampled randomly 0164 // (with uniform probability) for each collision, when the projectile is not an ion. 0165 // Note: comment out the corresponding line in order to exclude a particle. 0166 std::vector<G4String> vecProjectiles; //***LOOKHERE*** POSSIBLE HADRON PROJECTILES 0167 // vecProjectiles.push_back( "pi-" ); 0168 // Note: vecProjectiles.push_back( "pi0" ); // Excluded because too short-lived 0169 // vecProjectiles.push_back( "pi+" ); 0170 // vecProjectiles.push_back( "kaon-" ); 0171 // vecProjectiles.push_back( "kaon+" ); 0172 // vecProjectiles.push_back( "kaon0L" ); 0173 // vecProjectiles.push_back( "kaon0S" ); 0174 // Note: vecProjectiles.push_back( "eta" ); // Excluded because too short-lived 0175 // Note: vecProjectiles.push_back( "eta_prime" ); // Excluded because too short-lived 0176 vecProjectiles.push_back("proton"); 0177 // vecProjectiles.push_back( "neutron" ); 0178 // vecProjectiles.push_back( "deuteron" ); 0179 // vecProjectiles.push_back( "triton" ); 0180 // vecProjectiles.push_back( "He3" ); 0181 // vecProjectiles.push_back( "alpha" ); 0182 // vecProjectiles.push_back( "lambda" ); 0183 // vecProjectiles.push_back( "sigma-" ); 0184 // Note: vecProjectiles.push_back( "sigma0" ); // Excluded because too short-lived 0185 // vecProjectiles.push_back( "sigma+" ); 0186 // vecProjectiles.push_back( "xi-" ); 0187 // vecProjectiles.push_back( "xi0" ); 0188 // vecProjectiles.push_back( "omega-" ); 0189 // vecProjectiles.push_back( "anti_proton" ); 0190 // vecProjectiles.push_back( "anti_neutron" ); 0191 // vecProjectiles.push_back( "anti_lambda" ); 0192 // vecProjectiles.push_back( "anti_sigma-" ); 0193 // Note: vecProjectiles.push_back( "anti_sigma0" ); // Excluded because too short-lived 0194 // vecProjectiles.push_back( "anti_sigma+" ); 0195 // vecProjectiles.push_back( "anti_xi-" ); 0196 // vecProjectiles.push_back( "anti_xi0" ); 0197 // vecProjectiles.push_back( "anti_omega-" ); 0198 // vecProjectiles.push_back( "anti_deuteron" ); 0199 // vecProjectiles.push_back( "anti_triton" ); 0200 // vecProjectiles.push_back( "anti_He3" ); 0201 // vecProjectiles.push_back( "anti_alpha" ); 0202 // Charm and bottom hadrons 0203 // vecProjectiles.push_back( "D+" ); 0204 // vecProjectiles.push_back( "D-" ); 0205 // vecProjectiles.push_back( "D0" ); 0206 // vecProjectiles.push_back( "anti_D0" ); 0207 // vecProjectiles.push_back( "Ds+" ); 0208 // vecProjectiles.push_back( "Ds-" ); 0209 // Note: vecProjectiles.push_back( "etac" ); // Excluded because too short-lived 0210 // Note: vecProjectiles.push_back( "J/psi" ); // Excluded because too short-lived 0211 // vecProjectiles.push_back( "B+" ); 0212 // vecProjectiles.push_back( "B-" ); 0213 // vecProjectiles.push_back( "B0" ); 0214 // vecProjectiles.push_back( "anti_B0" ); 0215 // vecProjectiles.push_back( "Bs0" ); 0216 // vecProjectiles.push_back( "anti_Bs0" ); 0217 // vecProjectiles.push_back( "Bc+" ); 0218 // vecProjectiles.push_back( "Bc-" ); 0219 // Note: vecProjectiles.push_back( "Upsilon" ); // Excluded because too short-lived 0220 // vecProjectiles.push_back( "lambda_c+" ); 0221 // vecProjectiles.push_back( "anti_lambda_c+" ); 0222 // Note: vecProjectiles.push_back( "sigma_c+" ); // Excluded because too short-lived 0223 // Note: vecProjectiles.push_back( "anti_sigma_c+" ); // Excluded because too short-lived 0224 // Note: vecProjectiles.push_back( "sigma_c0" ); // Excluded because too short-lived 0225 // Note: vecProjectiles.push_back( "anti_sigma_c0" ); // Excluded because too short-lived 0226 // Note: vecProjectiles.push_back( "sigma_c++" ); // Excluded because too short-lived 0227 // Note: vecProjectiles.push_back( "anti_sigma_c++" ); // Excluded because too short-lived 0228 // vecProjectiles.push_back( "xi_c+" ); 0229 // vecProjectiles.push_back( "anti_xi_c+" ); 0230 // vecProjectiles.push_back( "xi_c0" ); 0231 // vecProjectiles.push_back( "anti_xi_c0" ); 0232 // vecProjectiles.push_back( "omega_c0" ); 0233 // vecProjectiles.push_back( "anti_omega_c0" ); 0234 // vecProjectiles.push_back( "lambda_b" ); 0235 // vecProjectiles.push_back( "anti_lambda_b" ); 0236 // Note: vecProjectiles.push_back( "sigma_b+" ); // Excluded because too short-lived 0237 // Note: vecProjectiles.push_back( "anti_sigma_b+" ); // Excluded because too short-lived 0238 // Note: vecProjectiles.push_back( "sigma_b0" ); // Excluded because too short-lived 0239 // Note: vecProjectiles.push_back( "sigma_b0" ); // Excluded because too short-lived 0240 // Note: vecProjectiles.push_back( "sigma_b-" ); // Excluded because too short-lived 0241 // Note: vecProjectiles.push_back( "anti_sigma_b-" ); // Excluded because too short-lived 0242 // vecProjectiles.push_back( "xi_b0" ); 0243 // vecProjectiles.push_back( "anti_xi_b0" ); 0244 // vecProjectiles.push_back( "xi_b-" ); 0245 // vecProjectiles.push_back( "anti_xi_b-" ); 0246 // vecProjectiles.push_back( "omega_b-" ); 0247 // vecProjectiles.push_back( "anti_omega_b-" ); 0248 0249 G4ParticleDefinition* projectileNucleus = nullptr; 0250 G4GenericIon* gion = G4GenericIon::GenericIon(); 0251 gion->SetProcessManager(new G4ProcessManager(gion)); 0252 G4ParticleTable* partTable = G4ParticleTable::GetParticleTable(); 0253 G4IonTable* ions = partTable->GetIonTable(); 0254 partTable->SetReadiness(); 0255 ions->CreateAllIon(); 0256 ions->CreateAllIsomer(); 0257 0258 //***LOOKHERE*** HADRON (false) OR ION (true) PROJECTILE ? 0259 const G4bool isProjectileIon = false; 0260 if (isProjectileIon) { 0261 minEnergy = 40.0 * 13.0 * CLHEP::GeV; //***LOOKHERE*** ION PROJECTILE MIN Ekin 0262 maxEnergy = 40.0 * 13.0 * CLHEP::GeV; //***LOOKHERE*** ION PROJECTILE MAX Ekin 0263 G4int ionZ = 18, ionA = 40; //***LOOKHERE*** ION PROJECTILE (Z, A) 0264 projectileNucleus = partTable->GetIonTable()->GetIon(ionZ, ionA, 0.0); 0265 } 0266 0267 // Vector of Geant4 NIST names of materials: one of this will be sampled randomly 0268 // (with uniform probability) for each collision and used as target material. 0269 // Note: comment out the corresponding line in order to exclude a material; 0270 // or, vice versa, add a new line to extend the list with another material. 0271 std::vector<G4String> vecMaterials; //***LOOKHERE*** : NIST TARGET MATERIALS 0272 // vecMaterials.push_back( "G4_H" ); 0273 // vecMaterials.push_back( "G4_He" ); 0274 // vecMaterials.push_back( "G4_Be" ); 0275 vecMaterials.push_back("G4_C"); 0276 // vecMaterials.push_back( "G4_Al" ); 0277 // vecMaterials.push_back( "G4_Si" ); 0278 // vecMaterials.push_back( "G4_Sc" ); 0279 // vecMaterials.push_back( "G4_Ar" ); 0280 // vecMaterials.push_back( "G4_Fe" ); 0281 // vecMaterials.push_back( "G4_Cu" ); 0282 // vecMaterials.push_back( "G4_W" ); 0283 // vecMaterials.push_back( "G4_Pb" ); 0284 0285 const G4int numProjectiles = vecProjectiles.size(); 0286 const G4int numMaterials = vecMaterials.size(); 0287 0288 G4cout << G4endl << "================= Configuration ==================" << G4endl 0289 << "Model: " << namePhysics << G4endl << "Ekin: [ " << minEnergy / CLHEP::GeV << " , " 0290 << maxEnergy / CLHEP::GeV << " ] GeV" << G4endl 0291 << "Number of collisions: " << numCollisions << G4endl 0292 << "Number of hadron projectiles: " << numProjectiles << G4endl 0293 << "Number of materials: " << numMaterials << G4endl 0294 << "IsIonProjectile: " << (projectileNucleus != nullptr ? "true \t" : "false") 0295 << (projectileNucleus != nullptr ? projectileNucleus->GetParticleName() : G4String("")) 0296 << G4endl << "===================================================" << G4endl << G4endl; 0297 0298 CLHEP::Ranlux64Engine defaultEngine(1234567, 4); 0299 CLHEP::HepRandom::setTheEngine(&defaultEngine); 0300 //***LOOKHERE*** RANDOM ENGINE START SEED 0301 // G4int seed = time( NULL ); 0302 // CLHEP::HepRandom::setTheSeed( seed ); 0303 // G4cout << G4endl << " Initial seed = " << seed << G4endl << G4endl; 0304 0305 // Set up histo manager. 0306 auto histoManager = FinalStateHistoManager(); 0307 histoManager.Book(); 0308 0309 // Instanciate the HadronicGenerator providing the name of the "physics case" 0310 HadronicGenerator* theHadronicGenerator = new HadronicGenerator(namePhysics); 0311 //**************************************************************************** 0312 0313 if (theHadronicGenerator == nullptr) { 0314 G4cerr << "ERROR: theHadronicGenerator is NULL !" << G4endl; 0315 return 1; 0316 } 0317 else if (!theHadronicGenerator->IsPhysicsCaseSupported()) { 0318 G4cerr << "ERROR: this physics case is NOT supported !" << G4endl; 0319 return 2; 0320 } 0321 0322 // Start timing 0323 auto start = std::chrono::high_resolution_clock::now(); 0324 0325 // Loop over the collisions 0326 G4double rnd1, rnd2, rnd3, rnd4, rnd5, rnd6, normalization, projectileEnergy; 0327 G4VParticleChange* aChange = nullptr; 0328 for (G4int i = 0; i < numCollisions; ++i) { 0329 histoManager.BeginOfEvent(); 0330 0331 // Draw some random numbers to select the hadron-nucleus interaction: 0332 // projectile hadron, projectile kinetic energy, projectile direction, and target material. 0333 rnd1 = CLHEP::HepRandom::getTheEngine()->flat(); 0334 rnd2 = CLHEP::HepRandom::getTheEngine()->flat(); 0335 rnd3 = CLHEP::HepRandom::getTheEngine()->flat(); 0336 rnd4 = CLHEP::HepRandom::getTheEngine()->flat(); 0337 rnd5 = CLHEP::HepRandom::getTheEngine()->flat(); 0338 rnd6 = CLHEP::HepRandom::getTheEngine()->flat(); 0339 // Sample the projectile kinetic energy 0340 projectileEnergy = minEnergy + rnd1 * (maxEnergy - minEnergy); 0341 if (projectileEnergy <= 0.0) projectileEnergy = minEnergy; 0342 // Sample the projectile direction 0343 normalization = 1.0 / std::sqrt(rnd2 * rnd2 + rnd3 * rnd3 + rnd4 * rnd4); 0344 //***LOOKHERE*** IF true THEN SMEAR DIRECTION 0345 const G4bool isOnSmearingDirection = false; 0346 //***LOOKHERE*** ELSE USE THIS FIXED DIRECTION 0347 G4ThreeVector aDirection = G4ThreeVector(0.0, 0.0, 1.0); 0348 if (isOnSmearingDirection) { 0349 aDirection = G4ThreeVector(normalization * rnd2, normalization * rnd3, normalization * rnd4); 0350 } 0351 // Sample the projectile hadron from the vector vecProjectiles 0352 G4int index_projectile = std::trunc(rnd5 * numProjectiles); 0353 G4String nameProjectile = vecProjectiles[index_projectile]; 0354 G4ParticleDefinition* projectile = partTable->FindParticle(nameProjectile); 0355 if (projectileNucleus) { 0356 nameProjectile = projectileNucleus->GetParticleName(); 0357 projectile = projectileNucleus; 0358 } 0359 // Sample the target material from the vector vecMaterials 0360 // (Note: the target nucleus will be sampled by Geant4) 0361 G4int index_material = std::trunc(rnd6 * numMaterials); 0362 G4String nameMaterial = vecMaterials[index_material]; 0363 G4Material* material = G4NistManager::Instance()->FindOrBuildMaterial(nameMaterial); 0364 if (material == nullptr) { 0365 G4cerr << "ERROR: Material " << nameMaterial << " is not found !" << G4endl; 0366 return 3; 0367 } 0368 if (isPrintingEnabled) { 0369 G4cout << "\t Collision " << i << " ; projectile=" << nameProjectile; 0370 if (projectileNucleus) { 0371 G4cout << " ; Ekin[MeV]/nucleon=" 0372 << projectileEnergy 0373 / static_cast<G4double>(std::abs(projectileNucleus->GetBaryonNumber())); 0374 } 0375 else { 0376 G4cout << " ; Ekin[MeV]=" << projectileEnergy; 0377 } 0378 G4cout << " ; direction=" << aDirection << " ; material=" << nameMaterial; 0379 } 0380 0381 // Call here the "hadronic generator" to get the secondaries produced by the hadronic collision 0382 aChange = theHadronicGenerator->GenerateInteraction( 0383 projectile, projectileEnergy, 0384 /* ********************************************** */ aDirection, material); 0385 0386 G4int nsec = aChange ? aChange->GetNumberOfSecondaries() : 0; 0387 G4bool isPrintingOfSecondariesEnabled = false; 0388 if (isPrintingEnabled) { 0389 G4cout << G4endl << "\t --> #secondaries=" << nsec 0390 << " ; impactParameter[fm]=" << theHadronicGenerator->GetImpactParameter() / fermi 0391 << " ; #projectileSpectatorNucleons=" 0392 << theHadronicGenerator->GetNumberOfProjectileSpectatorNucleons() 0393 << " ; #targetSpectatorNucleons=" 0394 << theHadronicGenerator->GetNumberOfTargetSpectatorNucleons() 0395 << " ; #NNcollisions=" << theHadronicGenerator->GetNumberOfNNcollisions() << G4endl; 0396 if (i % printingGap == 0) { 0397 isPrintingOfSecondariesEnabled = true; 0398 G4cout << "\t \t List of produced secondaries: " << G4endl; 0399 } 0400 } 0401 // Loop over produced secondaries and eventually print out some information. 0402 for (G4int j = 0; j < nsec; ++j) { 0403 const G4DynamicParticle* sec = aChange->GetSecondary(j)->GetDynamicParticle(); 0404 if (isPrintingOfSecondariesEnabled) { 0405 G4cout << "\t \t \t j=" << j << "\t" << sec->GetDefinition()->GetParticleName() 0406 << "\t p=" << sec->Get4Momentum() << " MeV" << G4endl; 0407 } 0408 0409 // Store each secondary. 0410 histoManager.ScoreSecondary(sec); 0411 0412 delete aChange->GetSecondary(j); 0413 } 0414 if (aChange) aChange->Clear(); 0415 histoManager.EndOfEvent(); 0416 } 0417 0418 histoManager.EndOfRun(); 0419 0420 G4cout << G4endl << " Final random number = " << CLHEP::HepRandom::getTheEngine()->flat() 0421 << G4endl; 0422 0423 const auto stop = std::chrono::high_resolution_clock::now(); 0424 const auto diff = stop - start; 0425 const auto time = 0426 static_cast<G4double>(std::chrono::duration_cast<std::chrono::microseconds>(diff).count()) 0427 / 1e6; 0428 G4cout << G4endl; 0429 G4cout << "Processed " << numCollisions << " events (collisions) in " << std::scientific << time 0430 << " seconds." 0431 << " Average: " << std::defaultfloat << (time * 1E3 / numCollisions) << " ms / event." 0432 << G4endl; 0433 G4cout << G4endl; 0434 0435 G4cout << "=== End of test ===" << G4endl; 0436 } 0437 0438 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |