Back to home page

EIC code displayed by LXR

 
 

    


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......