Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 09:22:02

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 PhysGeoImport.cc
0028 /// \brief Implementation of the PhysGeoImport class
0029 
0030 #include "PhysGeoImport.hh"
0031 #include "Randomize.hh"
0032 #include "G4Sphere.hh"
0033 #include "G4PhysicalConstants.hh"
0034 
0035 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0036 
0037 PhysGeoImport::PhysGeoImport() :
0038     fFactor(1.),
0039     fGeoName("")
0040 {
0041     DefineMaterial();
0042 }
0043 
0044 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0045 
0046 PhysGeoImport::PhysGeoImport(G4bool isVisu) :
0047     fIsVisu(isVisu),
0048     fFactor(1.),
0049     fGeoName("")
0050 {
0051     if (fIsVisu) G4cout<<" For Checking Visualization!"<<G4endl;
0052     DefineMaterial();
0053 }
0054 
0055 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0056 
0057 G4LogicalVolume* PhysGeoImport::CreateLogicVolume(const G4String& fileName,G4String& voxelName)
0058 {
0059     // The idea is to return a pointer to the mother volume of the input file as output.
0060     // Create a temporary material map to assign materials
0061 
0062     std::map<G4String, G4Material*> materials;
0063 
0064     // Loop on each material to build the map
0065     for(G4int i=0, ie=fMaterialVect.size(); i<ie; ++i)
0066     {
0067         G4String matName("");
0068 
0069         if(fMaterialVect[i]->GetName()=="adenine_PU") matName = "adenine";
0070         else if(fMaterialVect[i]->GetName()=="thymine_PY") matName = "thymine";
0071         else if(fMaterialVect[i]->GetName()=="guanine_PU") matName = "guanine";
0072         else if(fMaterialVect[i]->GetName()=="cytosine_PY") matName = "cytosine";
0073         else if(fMaterialVect[i]->GetName()=="backbone_THF") matName = "deoxyribose";
0074         else if(fMaterialVect[i]->GetName()=="backbone_TMP") matName = "phosphate";
0075         else if(fMaterialVect[i]->GetName()=="G4_WATER") matName = "water";
0076         else if(fMaterialVect[i]->GetName()=="homogeneous_dna") matName = "homogeneous_dna";
0077         else if(fMaterialVect[i]->GetName()=="G4_Galactic") matName = "vacuum";
0078         else
0079         {
0080             matName = fMaterialVect[i]->GetName();
0081         }
0082 
0083         materials[matName] = fMaterialVect[i];
0084     }
0085 
0086 
0087     // Parse the input file
0088 
0089     voxelName = ParseFile(fileName);
0090 
0091     // Create the volumes
0092 
0093     G4String boxNameSolid = fGeoName+"_solid";
0094     G4Box* box_solid = new G4Box(boxNameSolid, fSize/2, fSize/2, fSize/2);
0095 
0096     G4String boxNameLogic = fGeoName+"_logic";
0097     G4LogicalVolume* box_logic = new G4LogicalVolume(box_solid, fpWater, boxNameLogic);
0098 
0099     // sort the molecules
0100     std::sort(fMolecules.begin(), fMolecules.end() );
0101    
0102     // Loop on all the parsed molecules
0103     for(G4int i=0, ie=fMolecules.size(); i<ie; ++i)
0104     {
0105         // Retrieve general molecule informations
0106         //
0107         G4String name = fMolecules[i].fName;
0108         G4String materialName = "water";// fMolecules[i].fMaterial;
0109         G4double radius = fMolecules[i].fRadius;
0110         G4double waterRadius = fMolecules[i].fRadiusWater;
0111         G4ThreeVector moleculePosition = fMolecules[i].fPosition;
0112         G4int copyNum = fMolecules[i].fCopyNumber;
0113 
0114         // Water hydration shell volume part
0115 
0116         G4Orb* moleculeWater_solid = 0;
0117         G4VSolid* moleculeWaterCut_solid = 0;
0118         G4LogicalVolume* moleculeWater_logic = 0;
0119 
0120         // If water radius != 0 then we have a water hydration shell
0121         G4double tol = 0.0001;
0122         if(waterRadius > (0 + tol)*nm)
0123         {
0124             G4Material* mat = 0;
0125             
0126             mat=materials[materialName];
0127 
0128             G4String nameWaterSolid = name+"_water_solid";
0129             moleculeWater_solid = new G4Orb(nameWaterSolid, waterRadius);
0130             moleculeWaterCut_solid = CreateCutSolid(moleculeWater_solid, fMolecules[i], fMolecules, false);
0131 
0132             G4String nameWaterLogic = name+"_water_logic";
0133             moleculeWater_logic = new G4LogicalVolume(moleculeWaterCut_solid, mat, nameWaterLogic);
0134 
0135             G4String nameWaterPhys = name+"_water_phys";
0136             new G4PVPlacement(0, moleculePosition, moleculeWater_logic, nameWaterPhys, box_logic, false, copyNum);
0137         }
0138 
0139         // Dna volume part
0140 
0141         G4Orb* molecule_solid = 0;
0142         G4VSolid* moleculeCut_solid = 0;
0143         G4LogicalVolume* molecule_logic = 0;
0144 
0145         G4String nameSolid = fMolecules[i].fName+"_solid";
0146         molecule_solid = new G4Orb(nameSolid, radius);
0147         moleculeCut_solid = CreateCutSolid(molecule_solid, fMolecules[i], fMolecules, true);
0148 
0149         G4String nameLogic = name+"_logic";
0150         molecule_logic = new G4LogicalVolume(moleculeCut_solid, materials[materialName], nameLogic);
0151 
0152         // If there was a water hydration shell volume then the current dna volume is
0153         // placed within it and, thus, its relative coordinates are 0,0,0.
0154         if(waterRadius > (0 + tol)*nm)
0155         {
0156             G4ThreeVector position(0.,0.,0.);
0157             G4String namePhys = name+"_phys";
0158             new G4PVPlacement(0, position, molecule_logic, namePhys, moleculeWater_logic, false, copyNum);
0159         }
0160         // If not, coordinates are those of the molecule
0161         else
0162         {
0163             G4ThreeVector position = moleculePosition;
0164             G4String namePhys = name+"_phys";
0165             new G4PVPlacement(0, position, molecule_logic, namePhys, box_logic, false, copyNum);
0166         }
0167     }
0168 
0169     // Clear the containers
0170     fMolecules.clear();
0171     fRadiusMap.clear();
0172     fWaterRadiusMap.clear();
0173 
0174     return box_logic;
0175 }
0176 
0177 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0178 
0179 G4String PhysGeoImport::ParseFile(const G4String& fileName)
0180 {
0181     G4cout<<"Start parsing of "<<fileName<<G4endl;
0182 
0183     // Clear the containers
0184     fMolecules.clear();
0185     fRadiusMap.clear();
0186     fWaterRadiusMap.clear();
0187 
0188     // Setup the input stream
0189     std::ifstream file(fileName.c_str());
0190 
0191     // Check if the file was correctly opened
0192     if(!file.is_open())
0193     {
0194         // Geant4 exception
0195         G4String msg = fileName+" could not be opened";
0196         G4Exception("PhysGeoImport::ParseFile()", "Geo_InputFileNotOpened", FatalException, msg);
0197     }
0198 
0199     // Define the line string variable
0200     G4String line;
0201     G4int preBpCpNo = -1;
0202     G4int preHistoneCpNo =-1;
0203     G4int NoBp = 0;
0204     G4int NoHistone = 0;
0205     // Read the file line per line
0206     while(std::getline(file, line) )
0207     {
0208         // Check the line to determine if it is empty
0209         if(line.empty()) continue; // skip the line if it is empty
0210 
0211         // Data string stream
0212         std::istringstream issLine(line);
0213 
0214         // String to determine the first letter/word
0215         G4String firstItem;
0216 
0217         // Put the first letter/word within the string
0218         issLine >> firstItem;
0219 
0220         // Check first letter to determine if the line is data or comment
0221         if(firstItem=="#") continue; // skip the line if it is comment
0222 
0223         // Use the file
0224         else if(firstItem=="_Name")
0225         {
0226             G4String name;
0227             issLine >> name;
0228 
0229             fGeoName = name;
0230         }
0231         else if(firstItem=="_Size")
0232         {
0233             G4double size;
0234             issLine >> size;
0235             size *= fFactor*nm;
0236 
0237             fSize = size;
0238         }
0239         else if(firstItem == "_Version")
0240         {
0241 
0242         }
0243         else if(firstItem=="_Number")
0244         {
0245 
0246         }
0247         else if(firstItem=="_Radius")
0248         {
0249             G4String name;
0250             issLine >> name;
0251 
0252             G4double radius;
0253             issLine >> radius;
0254             radius *= fFactor*nm;
0255 
0256             G4double waterRadius;
0257             issLine >> waterRadius;
0258             waterRadius *= fFactor*nm;
0259 
0260             fRadiusMap[name] = radius;
0261             fWaterRadiusMap[name] = waterRadius;
0262         }
0263         else if(firstItem=="_pl")
0264         {
0265             G4String name;
0266             issLine >> name;
0267 
0268             G4String material;
0269             issLine >> material;
0270 
0271             G4int strand;
0272             issLine >> strand;
0273 
0274             G4int copyNumber;
0275             issLine >> copyNumber;
0276 
0277             if (name == "histone") {
0278                 if (copyNumber != preHistoneCpNo ) {
0279                     NoHistone ++;
0280                     preHistoneCpNo = copyNumber;
0281                 }
0282             } else {
0283                 if (copyNumber != preBpCpNo) {
0284                     NoBp++;
0285                     preBpCpNo = copyNumber;
0286                 }
0287             }
0288 
0289             G4double x;
0290             issLine >> x;
0291             x *= fFactor*nm;
0292 
0293             G4double y;
0294             issLine >> y;
0295             y *= fFactor*nm;
0296 
0297             G4double z;
0298             issLine >> z;
0299             z *= fFactor*nm;
0300 
0301             Molecule molecule(name, copyNumber, G4ThreeVector(x, y, z), fRadiusMap[name], fWaterRadiusMap[name], material, strand);
0302 
0303             fMolecules.push_back(molecule);
0304         }
0305         else
0306         {
0307             // Geant4 exception
0308             G4String msg = firstItem+" is not defined in the parser. Check the input file: "+fileName+".";
0309             G4Exception("PhysGeoImport::ParseFile()", "Geo_WrongParse", FatalException, msg);
0310         }
0311     }
0312 
0313     // Close the file once the reading is done
0314     file.close();
0315 
0316     G4cout<<"End parsing of "<<fileName<<G4endl;
0317     fVoxelNbHistoneMap.insert({fGeoName,NoHistone});
0318     fVoxelNbBpMap.insert({fGeoName,NoBp});
0319     return fGeoName;
0320 }
0321 
0322 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0323 
0324 G4VSolid* PhysGeoImport::CreateCutSolid(G4Orb *solidOrbRef,
0325                                                Molecule &molRef,
0326                                                std::vector<Molecule> &molList,
0327                                                G4bool in)
0328 {
0329     // The idea behing this method is to cut overlap volumes by selecting one of them (the reference) and checking all the other volumes (the targets).
0330     // If a reference and a target volumes are close enough to overlap they will be cut.
0331     // The reference is already selected when we enter this method.
0332 
0333     // Use the tiny space to differentiate the frontiers (may not be necessary)
0334     G4double tinySpace = 0.001*fFactor*nm;
0335 
0336     // Cutted solid to be returned
0337     G4SubtractionSolid* solidCut(NULL);
0338 
0339     // Some flags
0340     G4bool isCutted = false;
0341     G4bool isOurVol = false;
0342 
0343     // Radius of the molecule to cut
0344     G4double radiusRef;
0345     if(molRef.fRadiusWater==0) radiusRef = molRef.fRadius;
0346     else radiusRef = molRef.fRadiusWater;
0347 
0348     // Reference volume position
0349     G4ThreeVector posRef = molRef.fPosition;
0350     // Before looping on all the volumes we check if the current 
0351     //reference volume overlaps with its container voxel boundaries.
0352     if(std::abs(posRef.x() ) + radiusRef > fSize/2 // along x
0353             || std::abs(posRef.y() ) + radiusRef > fSize/2 // along y
0354             || std::abs(posRef.z() ) + radiusRef > fSize/2) // along z
0355     {
0356         // If we enter here, then the reference volume overlaps with the boundaries of the container voxel
0357         // Box used to cut
0358         G4Box* solidBox = new G4Box("solid_box_for_cut", fSize/2, fSize/2, fSize/2);
0359         G4ThreeVector posBox;
0360 
0361         // Create a dummy rotation matrix
0362         G4RotationMatrix *rotMat = new G4RotationMatrix;
0363         rotMat->rotate(0, G4ThreeVector(0,0,1) );
0364 
0365         // To choose the cut direction
0366 
0367         // Up
0368         if(std::abs( posRef.y() + radiusRef ) > fSize/2 )
0369         {
0370            posBox = -posRef +  G4ThreeVector(0,fSize,0);
0371 
0372             // If the volume is cutted for the first time
0373             if(!isCutted)
0374             {
0375                 solidCut = new G4SubtractionSolid("solidCut", solidOrbRef, solidBox, rotMat, posBox);
0376                 isCutted = true;
0377             }
0378             // For the other times
0379             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, posBox);
0380         }
0381 
0382         // Down
0383         if(std::abs( posRef.y() - radiusRef ) > fSize/2 )
0384         {
0385             posBox = -posRef + G4ThreeVector(0,-fSize,0);
0386 
0387             // If the volume is cutted for the first time
0388             if(!isCutted)
0389             {
0390                 solidCut = new G4SubtractionSolid("solidCut", solidOrbRef,solidBox,rotMat, posBox);
0391             isCutted = true;
0392         }
0393             // For the other times
0394             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, posBox);
0395         }
0396 
0397         // Left
0398         if(std::abs( posRef.x() + radiusRef ) > fSize/2 )
0399         {
0400             posBox = -posRef + G4ThreeVector(fSize,0,0);
0401 
0402             // If the volume is cutted for the first time
0403             if(!isCutted)
0404             {
0405                 solidCut = new G4SubtractionSolid("solidCut", solidOrbRef, solidBox, rotMat, posBox);
0406                 isCutted = true;
0407             }
0408             // For the other times
0409             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, posBox);
0410         }
0411 
0412         // Right
0413         if(std::abs( posRef.x() - radiusRef ) > fSize/2 )
0414         {
0415             posBox = -posRef + G4ThreeVector(-fSize,0,0);
0416 
0417             // If the volume is cutted for the first time
0418             if(!isCutted)
0419             {
0420                 solidCut = new G4SubtractionSolid("solidCut", solidOrbRef, solidBox, rotMat, posBox);
0421                 isCutted = true;
0422             }
0423             // For the other times
0424             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, posBox);
0425         }
0426 
0427         // Forward
0428         if(std::abs( posRef.z() + radiusRef ) > fSize/2 )
0429         {
0430             posBox = -posRef + G4ThreeVector(0,0,fSize);
0431 
0432             // If the volume is cutted for the first time
0433             if(!isCutted)
0434             {
0435                 solidCut = new G4SubtractionSolid("solidCut", solidOrbRef, solidBox, rotMat, posBox);
0436                 isCutted = true;
0437             }
0438             // For the other times
0439             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, posBox);
0440         }
0441 
0442         // Backward
0443         if(std::abs( posRef.z() - radiusRef ) > fSize/2 )
0444         {
0445             posBox = -posRef + G4ThreeVector(0,0,-fSize);
0446 
0447             // If the volume is cutted for the first time
0448             if(!isCutted)
0449             {
0450                 solidCut = new G4SubtractionSolid("solidCut", solidOrbRef, solidBox, rotMat, posBox);
0451                 isCutted = true;
0452             }
0453             // For the other times
0454             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, posBox);
0455         }
0456     }
0457 
0458     // Look the other volumes of the voxel
0459     // Loop on all the target volumes (other volumes with potential overlaps)
0460     for(G4int i=0, ie=molList.size(); i<ie; ++i)
0461     {
0462         G4ThreeVector posTar = molList[i].fPosition;
0463 
0464         G4double rTar = posRef.z();
0465         G4double zTar = posTar.z();
0466 
0467         if(zTar>rTar+20*fFactor*nm)
0468         {
0469             break;
0470         }
0471         else if(zTar<rTar-20*fFactor*nm)
0472         {
0473             continue;
0474         }
0475 
0476         // Retrieve current target sphere informations
0477         G4double radiusTar;
0478         if(molList[i].fRadiusWater==0) radiusTar = molList[i].fRadius;
0479         else radiusTar = molList[i].fRadiusWater;
0480 
0481         // Compute the distance reference-target
0482         G4double distance = std::abs( (posRef - posTar).getR() );
0483 
0484         // Use the distance to check if the current target is also the reference.
0485         // This can only happen once per loop.
0486         if(distance==0 && !isOurVol)
0487         {
0488             // Target volume is also reference volume.
0489 
0490             // Set the flag
0491             isOurVol = true;
0492 
0493             // Next iteration
0494             continue;
0495         }
0496         // If the condition is correct more than one time then there is a mistake somewhere.
0497         else if(distance == 0 && isOurVol)
0498         {
0499             G4ExceptionDescription desmsg;
0500             desmsg << "DetectorConstruction::CreateCutSolid: Two volumes are placed at the same position.";
0501             G4Exception("ChemGeoImport::BuildGeometry", "", FatalException, desmsg);
0502         }
0503 
0504         // If the volumes are differents then we want to know if they are
0505         // close enough to overlap and, thus, to intiate a cut.
0506         else if(distance <= radiusRef+radiusTar)
0507         {
0508             // Volumes are close enough, there will be a cut
0509 
0510             // Box used to cut
0511             G4Box* solidBox = new G4Box("solid_box_for_cut", 2*radiusTar, 2*radiusTar, 2*radiusTar);
0512 
0513             // This part is tricky.
0514             // The goal is to calculate the position of the intersection center
0515 
0516             // diff vector to from ref to tar
0517             G4ThreeVector diff = posTar - posRef;
0518 
0519             // Find the intersection point and add to it half the length of the box used to cut
0520             G4double d = (std::pow(radiusRef,2)-std::pow(radiusTar,2)+std::pow(distance,2) ) / 
0521                         (2*distance) + solidBox->GetZHalfLength() - tinySpace;
0522 
0523             // If we are in another volume we choose to double the tinySpace to 
0524             //differentiate without ambiguities the inner and outer volume frontiers.
0525             // (may not be necessary)
0526             if(in) d -= 2*tinySpace;
0527 
0528             // Position of the box in order to achieve the cut.
0529             // "* ( diff/diff.getR() )" is necessary to get a vector in the right direction as output
0530             G4ThreeVector pos = d *( diff/diff.getR() );
0531 
0532             // Get the rotation angles because the box used to cut needs to be rotated
0533             // to give the right "cut angle".
0534             G4double phi = std::acos(pos.getZ()/pos.getR());
0535             G4double theta = std::acos( pos.getX() / ( pos.getR()*std::cos(pi/2.-phi) ) );
0536 
0537             if(pos.getY()<0) theta = -theta;
0538 
0539             G4ThreeVector rotAxisForPhi(1*fFactor*nm,0.,0.);
0540             rotAxisForPhi.rotateZ(theta+pi/2);
0541 
0542             // Create the rotation matrix
0543             G4RotationMatrix *rotMat = new G4RotationMatrix;
0544             rotMat->rotate(-phi, rotAxisForPhi);
0545 
0546             // Rotate it again
0547             G4ThreeVector rotZAxis(0.,0.,1*fFactor*nm);
0548             rotMat->rotate(theta, rotZAxis);
0549 
0550             // If the volume is cutted for the first time
0551             if(!isCutted) solidCut = new G4SubtractionSolid("solidCut", solidOrbRef, 
0552             solidBox, rotMat, pos);
0553 
0554             // For the other times
0555             else solidCut = new G4SubtractionSolid("solidCut", solidCut, solidBox, rotMat, pos);
0556 
0557             // Set the cut flag
0558             isCutted = true;
0559         }
0560     }
0561 
0562     // If there was at least one cut then we return the cutted volume
0563     if(isCutted) return solidCut;
0564 
0565     // Otherwise, we return the original volume
0566     else return solidOrbRef;
0567     
0568 }
0569 
0570 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0571 
0572 void PhysGeoImport::DefineMaterial()
0573 {
0574     G4NistManager * man = G4NistManager::Instance();
0575     fpWater = man->FindOrBuildMaterial("G4_WATER");
0576     fMaterialVect.push_back(fpWater);
0577     fVacuum = man->FindOrBuildMaterial("G4_Galactic");
0578     fMaterialVect.push_back(fVacuum);
0579 
0580     G4double z, a, density;
0581     G4String name, symbol;
0582     G4int nComponents, nAtoms;
0583 
0584     a = 12.0107*g/mole;
0585     G4Element* elC = new G4Element(name="Carbon", symbol="C", z=6., a);
0586     a = 1.00794*g/mole;
0587     G4Element* elH  = new G4Element(name="Hydrogen",symbol="H" , z= 1., a);
0588     a = 15.9994*g/mole;
0589     G4Element* elO  = new G4Element(name="Oxygen"  ,symbol="O" , z= 8., a);
0590     a = 14.00674*g/mole;
0591     G4Element* elN  = new G4Element(name="Nitrogen"  ,symbol="N" , z= 7., a);
0592     a = 30.973762*g/mole;
0593     G4Element* elP  = new G4Element(name="Phosphorus"  ,symbol="P" , z= 15., a);
0594 
0595     density = 1.*g/cm3;
0596 
0597     fTHF = new G4Material("THF", density, nComponents=3);
0598     fTHF->AddElement(elC, nAtoms=4);
0599     fTHF->AddElement(elH, nAtoms=8);
0600     fTHF->AddElement(elO, nAtoms=1);
0601 
0602     fPY = new G4Material("PY", density, nComponents=3);
0603     fPY->AddElement(elC, nAtoms=4);
0604     fPY->AddElement(elH, nAtoms=4);
0605     fPY->AddElement(elN, nAtoms=2);
0606 
0607     fPU = new G4Material("PU", density, nComponents=3);
0608     fPU->AddElement(elC, nAtoms=5);
0609     fPU->AddElement(elH, nAtoms=4);
0610     fPU->AddElement(elN, nAtoms=4);
0611 
0612     fTMP = new G4Material("TMP", density,4);
0613     fTMP->AddElement(elC, nAtoms=3);
0614     fTMP->AddElement(elH, nAtoms=6);
0615     fTMP->AddElement(elP, nAtoms=1);
0616     fTMP->AddElement(elO, nAtoms=4);
0617 
0618     fMaterialVect.push_back(fTHF);
0619     fMaterialVect.push_back(fPY);
0620     fMaterialVect.push_back(fPU);
0621     fMaterialVect.push_back(fTMP);
0622 
0623     // Mixture creation
0624     fSugarMixt = new G4Material("sugarMixt", density, nComponents=2);
0625     fSugarMixt->AddMaterial(fTHF,0.5);
0626     fSugarMixt->AddMaterial(fTMP,0.5);
0627     fMaterialVect.push_back(fSugarMixt);
0628 
0629     // Real DNA materials creation
0630     //
0631     // Density calculation:
0632     //
0633     // d=m/V and M=m/n <=> m = M*n
0634     // <=> d = M*n/V
0635     // <=> d = (M*nb)/(Na*V)
0636 
0637     G4double MBackbone = (5.*12.0104 + 10.*1.00794 + 4.*15.9994)*g/mole;
0638     G4double VBackbone = 1.823912/20. * std::pow(1.e-9, 3.) *m3;
0639     G4double densityBaTHF = (MBackbone/(g/mole) * 1. )/(6.022e23*VBackbone/cm3) *g/cm3; // g/cm3
0640 
0641     fDeoxyribose = new G4Material("backbone_THF", densityBaTHF, nComponents=3);
0642     fDeoxyribose->AddElement(elC, nAtoms=5);
0643     fDeoxyribose->AddElement(elH, nAtoms=10);
0644     fDeoxyribose->AddElement(elO, nAtoms=4);
0645     fMaterialVect.push_back(fDeoxyribose);
0646 
0647     MBackbone = (3.*1.00794 + 1.*30.973762 + 4.*15.9994)*g/mole;
0648     VBackbone = 1.19114/20. * std::pow(1.e-9, 3.) *m3;
0649     G4double densityBaTMP = (MBackbone/(g/mole) * 1. )/(6.022e23*VBackbone/cm3) *g/cm3; // g/cm3
0650 
0651     fPhosphate = new G4Material("backbone_TMP", densityBaTMP,3);
0652     fPhosphate->AddElement(elH, nAtoms=3);
0653     fPhosphate->AddElement(elP, nAtoms=1);
0654     fPhosphate->AddElement(elO, nAtoms=4);
0655     fMaterialVect.push_back(fPhosphate);
0656 
0657     G4double MCytosine = (4.*12.0104 + 5.*1.00794 + 3.*14.0067 + 1.*15.9994)*g/mole;
0658     G4double VBase = 1.8527205/20. * std::pow(1.e-9, 3.) *m3;
0659     G4double densityCy = (MCytosine/(g/mole) * 1. )/(6.022e23*VBase/cm3) *g/cm3; // g/cm3
0660 
0661     fCytosine_PY = new G4Material("cytosine_PY", densityCy, nComponents=4);
0662     fCytosine_PY->AddElement(elC, nAtoms=4);
0663     fCytosine_PY->AddElement(elH, nAtoms=5);
0664     fCytosine_PY->AddElement(elN, nAtoms=3);
0665     fCytosine_PY->AddElement(elO, nAtoms=1);
0666     fMaterialVect.push_back(fCytosine_PY);
0667 
0668     G4double MThy = (5.*12.0104 + 6.*1.00794 + 2.*14.0067 + 2.*15.9994)*g/mole;
0669     VBase = 1.8527205/20. * std::pow(1.e-9, 3.) *m3;
0670     densityCy = (MThy/(g/mole) * 1. )/(6.022e23*VBase/cm3) *g/cm3; // g/cm3
0671 
0672     fThymine_PY = new G4Material("thymine_PY", densityCy, nComponents=4);
0673     fThymine_PY->AddElement(elC, nAtoms=5);
0674     fThymine_PY->AddElement(elH, nAtoms=6);
0675     fThymine_PY->AddElement(elN, nAtoms=2);
0676     fThymine_PY->AddElement(elO, nAtoms=2);
0677     fMaterialVect.push_back(fThymine_PY);
0678 
0679     G4double MAdenine = (5.*12.0104 + 5.*1.00794 + 5.*14.0067)*g/mole;
0680     VBase = 1.8527205/20. * std::pow(1.e-9, 3.) *m3;
0681     G4double densityAd = (MAdenine/(g/mole) * 1. )/(6.022e23*VBase/cm3) *g/cm3; // g/cm3
0682 
0683     fAdenine_PU = new G4Material("adenine_PU", densityAd, nComponents=3);
0684     fAdenine_PU->AddElement(elC, nAtoms=5);
0685     fAdenine_PU->AddElement(elH, nAtoms=5);
0686     fAdenine_PU->AddElement(elN, nAtoms=5);
0687     fMaterialVect.push_back(fAdenine_PU);
0688 
0689     MAdenine = (5.*12.0104 + 5.*1.00794 + 5.*14.0067 + 1.*15.999)*g/mole;
0690     VBase = 1.8527205/20. * std::pow(1.e-9, 3.) *m3;
0691     densityAd = (MAdenine/(g/mole) * 1. )/(6.022e23*VBase/cm3) *g/cm3; // g/cm3
0692 
0693     fGuanine_PU = new G4Material("guanine_PU", densityAd, nComponents=4);
0694     fGuanine_PU->AddElement(elC, nAtoms=5);
0695     fGuanine_PU->AddElement(elH, nAtoms=5);
0696     fGuanine_PU->AddElement(elN, nAtoms=5);
0697     fGuanine_PU->AddElement(elO, nAtoms=1);
0698     fMaterialVect.push_back(fGuanine_PU);
0699 
0700     fHomogeneous_dna = new G4Material("homogeneous_dna", 19.23e-21/(12.30781*1.e-21)  *g/cm3, nComponents=7);//21
0701     fHomogeneous_dna->AddMaterial(fpWater, 0.37);
0702     fHomogeneous_dna->AddMaterial(fDeoxyribose, 0.23);
0703     fHomogeneous_dna->AddMaterial(fPhosphate, 0.17);
0704     fHomogeneous_dna->AddMaterial(fAdenine_PU, 0.06);
0705     fHomogeneous_dna->AddMaterial(fGuanine_PU, 0.07);
0706     fHomogeneous_dna->AddMaterial(fCytosine_PY, 0.05);
0707     fHomogeneous_dna->AddMaterial(fThymine_PY, 0.05);
0708 
0709     fMaterialVect.push_back(fHomogeneous_dna);
0710 }
0711 
0712 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0713 
0714 G4LogicalVolume* PhysGeoImport::CreateNucleusLogicVolume(const G4String& fileName)
0715 {
0716     // Here, we parse the nucleus file and build a logical Geant4 volume from it.
0717 
0718     G4cout<<"Start the nucleus creation..."<<G4endl;
0719 
0720     G4VSolid* nucleusSolid = 0;
0721     G4LogicalVolume* nucleusLogic = 0;
0722 
0723     G4bool isNucleusBuild (false);
0724 
0725     // Open the world file
0726     std::ifstream nucleusFile;
0727     nucleusFile.open(fileName.c_str());
0728 
0729     // Check if the file was correctly opened
0730     if(!nucleusFile.is_open())
0731     {
0732         // Geant4 exception
0733         G4String msg = fileName+" could not be opened";
0734         G4Exception("PhysGeoImport::ParseFile()", "Geo_InputFileNotOpened", FatalException, msg);
0735     }
0736 
0737     // Define the line string variable
0738     G4String line;
0739 
0740     // Read the file line per line
0741     while(std::getline(nucleusFile, line) && !isNucleusBuild)
0742     {
0743         // Check the line to determine if it is empty
0744         if(line.empty()) continue; // skip the line if it is empty
0745 
0746         // Data string stream
0747         std::istringstream issLine(line);
0748 
0749         // String to determine the first letter/word
0750         G4String firstItem;
0751 
0752         // Put the first letter/word within the string
0753         issLine >> firstItem;
0754 
0755         // Check first letter to determine if the line is data or comment
0756         if(firstItem=="#") continue; // skip the line if it is comment
0757 
0758         // Use the file
0759 
0760         else if(firstItem == "_Name")
0761         {
0762             issLine >> fNucleusName;
0763         }
0764 
0765         else if(firstItem=="_Type")
0766         {
0767             issLine >> fNucleusType;
0768 
0769             if (fNucleusType == "Ellipsoid")
0770             {
0771                 G4float semiX, semiY, semiZ;
0772 
0773                 issLine >> semiX >> semiY >> semiZ;
0774 
0775                 semiX *= fFactor*nm;
0776                 semiY *= fFactor*nm;
0777                 semiZ *= fFactor*nm;
0778 
0779                 fNucleusData["SemiX"] = semiX;
0780                 fNucleusData["SemiY"] = semiY;
0781                 fNucleusData["SemiZ"] = semiZ;
0782 
0783                 nucleusSolid = new G4Ellipsoid(fNucleusName, semiX, semiY, semiZ);
0784                 nucleusLogic = new G4LogicalVolume(nucleusSolid, fpWater, "nucleus_logic");
0785                 G4double r3 = semiX*semiY*semiZ/m3;
0786                 fNucleusVolume = 4.0*pi*r3/3.0;
0787             } else if (fNucleusType == "EllipticCylinder") {
0788                 G4float semiX, semiY, semiZ;
0789         
0790                 issLine >> semiX >> semiY >> semiZ;
0791         
0792                 semiX *= fFactor*nm;
0793                 semiY *= fFactor*nm;
0794                 semiZ *= fFactor*nm;
0795         
0796                 fNucleusData["SemiX"] = semiX;
0797                 fNucleusData["SemiY"] = semiY;
0798                 fNucleusData["SemiZ"] = semiZ;
0799 
0800                 nucleusSolid = new G4EllipticalTube(fNucleusName, semiX, semiY, semiZ);
0801                 nucleusLogic = new G4LogicalVolume(nucleusSolid, fpWater, "nucleus_logic");
0802                 G4double r3 = 2*semiX*semiY*semiZ/m3; // multiplied by 2 cuz semiZ is hafl of height
0803                 fNucleusVolume = pi*r3;
0804             } else if (fNucleusType == "Spherical") {
0805                 G4float radius;
0806                 issLine >> radius;
0807                 radius *= fFactor*nm;
0808                 fNucleusData["SemiX"] = radius;
0809                 fNucleusData["SemiY"] = radius;
0810                 fNucleusData["SemiZ"] = radius;
0811                 nucleusSolid = new G4Orb(fNucleusName,radius);
0812                 nucleusLogic = new G4LogicalVolume(nucleusSolid, fpWater, "nucleus_logic");
0813                 G4double r3 = radius*radius*radius/m3;
0814                 fNucleusVolume = 4.0*pi*r3/3.0;
0815             } else {
0816                 G4String msg =fNucleusType+" is not registered.";
0817                 G4Exception("PhysGeoImport::CreateNucleusLogicVolume()", 
0818                 "Geo_InputFile_Unknown_Nucleus", FatalException, msg);
0819             }
0820 
0821             isNucleusBuild = true;
0822         }
0823     }
0824 
0825     nucleusFile.close();
0826 
0827     if(!isNucleusBuild)
0828     {
0829         G4String msg = "Nucleus data were not found for "+fNucleusType;
0830         G4Exception("PhysGeoImport::CreateNucleusLogicVolume()", 
0831         "Geo_InputFile_Unknown_Nucleus", FatalException, msg);
0832     }
0833 
0834     return nucleusLogic;
0835 }
0836 
0837 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
0838 
0839 std::vector<Voxel>* PhysGeoImport::CreateVoxelsData(const G4String& fileName)
0840 {
0841     fTotalNbBpPlacedInGeo = 0;
0842     fTotalNbHistonePlacedInGeo = 0;
0843     G4cout<<"Start the voxel data generation..."<<G4endl;
0844 
0845     std::vector<Voxel>* voxels = new std::vector<Voxel>;
0846 
0847     // Clear any previously loaded world
0848     voxels->clear();
0849 
0850     voxels->reserve(1000000);
0851 
0852     // Open the world file
0853     std::ifstream nucleusFile;
0854     nucleusFile.open(fileName.c_str());
0855 
0856     // Check if the file was correctly opened
0857     if(!nucleusFile.is_open())
0858     {
0859         // Geant4 exception
0860         G4String msg = fileName+" could not be opened";
0861         G4Exception("PhysGeoImport::ParseFile()", "Geo_InputFileNotOpened", FatalException, msg);
0862     }
0863 
0864     // Initialise the copy number to 0
0865     G4int voxelCopyNumber = 0;
0866 
0867     // Define the line string variable
0868     G4String line;
0869 
0870     auto whatchromatintype = [] (Voxel::VoxelType voxt) -> ChromatinType {
0871         if (voxt == Voxel::Straight || voxt == Voxel::Left || voxt == Voxel::Right ||
0872             voxt == Voxel::Up || voxt == Voxel::Down) return ChromatinType::fHeterochromatin;
0873         else if (voxt == Voxel::Straight2 || voxt == Voxel::Left2 || voxt == Voxel::Right2 ||
0874             voxt == Voxel::Up2 || voxt == Voxel::Down2) return ChromatinType::fEuchromatin;
0875         else return ChromatinType::fUnspecified;   
0876     };
0877     // Read the file line per line
0878     while(std::getline(nucleusFile, line) )
0879     {
0880         // Check the line to determine if it is empty
0881         if(line.empty()) continue; // skip the line if it is empty
0882 
0883         // Data string stream
0884         std::istringstream issLine(line);
0885 
0886         // String to determine the first letter/word
0887         G4String firstItem;
0888 
0889         // Put the first letter/word within the string
0890         issLine >> firstItem;
0891 
0892         // Check first letter to determine if the line is data or comment
0893         if(firstItem=="#") continue; // skip the line if it is comment
0894 
0895         // Use the file
0896 
0897         else if(firstItem == "_pl")
0898         {
0899             // Set the flags
0900 
0901             G4String name;
0902             issLine >> name;
0903 
0904             G4int chromoCpN;
0905             issLine >> chromoCpN;
0906 
0907             G4int domainCpN;
0908             issLine >> domainCpN;
0909 
0910             G4double x;
0911             issLine >> x;
0912             x *= fFactor*nm;
0913 
0914             G4double y;
0915             issLine >> y;
0916             y *= fFactor*nm;
0917 
0918             G4double z;
0919             issLine >> z;
0920             z *= fFactor*nm;
0921             
0922             G4double xx;
0923             issLine >> xx;
0924             
0925             G4double yx;
0926             issLine >> yx;
0927             
0928             G4double zx;
0929             issLine >> zx;
0930             
0931             G4double xy;
0932             issLine >> xy;
0933             
0934             G4double yy;
0935             issLine >> yy;
0936             
0937             G4double zy;
0938             issLine >> zy;
0939             
0940             G4double xz;
0941             issLine >> xz;
0942             
0943             G4double yz;
0944             issLine >> yz;
0945             
0946             G4double zz;
0947             issLine >> zz;
0948             
0949 
0950             G4RotationMatrix* rot = new G4RotationMatrix(G4ThreeVector(xx,xy,xz),
0951             G4ThreeVector(yx,yy,yz),G4ThreeVector(zx,zy,zz));
0952 
0953             Voxel::VoxelType type = Voxel::Other;
0954 
0955             if(name=="voxelStraight" || name=="VoxelStraight")
0956             {
0957                 type = Voxel::Straight;
0958             }
0959             else if(name=="voxelUp" || name=="VoxelUp")
0960             {
0961                 type = Voxel::Up;
0962             }
0963             else if(name=="voxelDown" || name=="VoxelDown")
0964             {
0965                 type = Voxel::Down;
0966             }
0967             else if(name=="voxelRight" || name=="VoxelRight")
0968             {
0969                 type = Voxel::Right;
0970             }
0971             else if(name=="voxelLeft" || name=="VoxelLeft")
0972             {
0973                 type = Voxel::Left;
0974             }
0975             else if(name=="voxelStraight2" || name=="VoxelStraight2")
0976             {
0977                 type = Voxel::Straight2;
0978             }
0979             else if(name=="voxelUp2" || name=="VoxelUp2")
0980             {
0981                 type = Voxel::Up2;
0982             }
0983             else if(name=="voxelDown2" || name=="VoxelDown2")
0984             {
0985                 type = Voxel::Down2;
0986             }
0987             else if(name=="voxelRight2" || name=="VoxelRight2")
0988             {
0989                 type = Voxel::Right2;
0990             }
0991             else if(name=="voxelLeft2" || name=="VoxelLeft2")
0992             {
0993                 type = Voxel::Left2;
0994             }
0995             else
0996             {
0997                 G4ExceptionDescription msg ;
0998                 msg << "The voxel named "<<name<<" is not registered in the parser";
0999                 G4Exception("PhysGeoImport::CreateVoxelsData", "", FatalException, msg, "");
1000             }
1001 
1002             voxels->push_back(Voxel(voxelCopyNumber, chromoCpN, domainCpN, type, 
1003             G4ThreeVector(x,y,z), rot) );
1004             fTotalNbBpPlacedInGeo += fVoxelNbBpMap[name];
1005             fTotalNbHistonePlacedInGeo += fVoxelNbHistoneMap[name];
1006             voxelCopyNumber++;
1007             auto chromatintype =  whatchromatintype(type);
1008             if (fChromatinTypeCount.find(chromatintype) == fChromatinTypeCount.end()) 
1009                 fChromatinTypeCount.insert({chromatintype,1});
1010             else fChromatinTypeCount[chromatintype]++;
1011         }
1012     }
1013 
1014     nucleusFile.close();
1015 
1016     G4cout<<"End the voxel data generation"<<G4endl;
1017 
1018     return voxels;
1019 }
1020 
1021 //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......