File indexing completed on 2025-02-23 09:21:44
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include "DicomDetectorConstruction.hh"
0032
0033 #include "CLHEP/Units/SystemOfUnits.h"
0034 #include "DicomHandler.hh"
0035 #include "DicomPhantomZSliceHeader.hh"
0036
0037 #include "G4Box.hh"
0038 #include "G4Element.hh"
0039 #include "G4LogicalVolume.hh"
0040 #include "G4Material.hh"
0041 #include "G4NistManager.hh"
0042 #include "G4PVPlacement.hh"
0043 #include "G4PhysicalConstants.hh"
0044 #include "G4UIcommand.hh"
0045 #include "G4VPhysicalVolume.hh"
0046 #include "globals.hh"
0047
0048 #ifdef G4_DCMTK
0049 # include "DicomFileMgr.hh"
0050 #endif
0051 #include "G4VisAttributes.hh"
0052
0053 using CLHEP::cm3;
0054 using CLHEP::g;
0055 using CLHEP::m;
0056 using CLHEP::mg;
0057 using CLHEP::mole;
0058 using CLHEP::perCent;
0059
0060
0061 DicomDetectorConstruction::DicomDetectorConstruction()
0062 : G4VUserDetectorConstruction(),
0063 fAir(0),
0064
0065 fWorld_solid(0),
0066 fWorld_logic(0),
0067 fWorld_phys(0),
0068
0069 fContainer_solid(0),
0070 fContainer_logic(0),
0071 fContainer_phys(0),
0072
0073 fNoFiles(0),
0074 fMateIDs(0),
0075
0076 fZSliceHeaderMerged(0),
0077
0078 fNoVoxelsX(0),
0079 fNoVoxelsY(0),
0080 fNoVoxelsZ(0),
0081 fVoxelHalfDimX(0),
0082 fVoxelHalfDimY(0),
0083 fVoxelHalfDimZ(0),
0084
0085 fConstructed(false)
0086 {}
0087
0088
0089 DicomDetectorConstruction::~DicomDetectorConstruction() {}
0090
0091
0092 G4VPhysicalVolume* DicomDetectorConstruction::Construct()
0093 {
0094 if (!fConstructed || fWorld_phys == 0) {
0095 fConstructed = true;
0096 InitialisationOfMaterials();
0097
0098
0099 G4double worldXDimension = 1. * m;
0100 G4double worldYDimension = 1. * m;
0101 G4double worldZDimension = 1. * m;
0102
0103 fWorld_solid = new G4Box("WorldSolid", worldXDimension, worldYDimension, worldZDimension);
0104
0105 fWorld_logic = new G4LogicalVolume(fWorld_solid, fAir, "WorldLogical", 0, 0, 0);
0106
0107 fWorld_phys = new G4PVPlacement(0, G4ThreeVector(0, 0, 0), "World", fWorld_logic, 0, false, 0);
0108
0109 fWorld_logic->SetVisAttributes(G4VisAttributes::GetInvisible());
0110
0111 #ifdef G4_DCMTK
0112 ReadPhantomDataNew();
0113 ConstructPhantomContainerNew();
0114 #else
0115 ReadPhantomData();
0116 ConstructPhantomContainer();
0117 #endif
0118
0119 ConstructPhantom();
0120 }
0121 return fWorld_phys;
0122 }
0123
0124
0125 void DicomDetectorConstruction::InitialisationOfMaterials()
0126 {
0127
0128 G4double z, a, density;
0129 G4String name, symbol;
0130
0131 G4Element* elC = new G4Element(name = "Carbon", symbol = "C", z = 6.0, a = 12.011 * g / mole);
0132 G4Element* elH = new G4Element(name = "Hydrogen", symbol = "H", z = 1.0, a = 1.008 * g / mole);
0133 G4Element* elN = new G4Element(name = "Nitrogen", symbol = "N", z = 7.0, a = 14.007 * g / mole);
0134 G4Element* elO = new G4Element(name = "Oxygen", symbol = "O", z = 8.0, a = 16.00 * g / mole);
0135 G4Element* elNa =
0136 new G4Element(name = "Sodium", symbol = "Na", z = 11.0, a = 22.98977 * g / mole);
0137 G4Element* elMg =
0138 new G4Element(name = "Magnesium", symbol = "Mg", z = 12.0, a = 24.3050 * g / mole);
0139 G4Element* elP =
0140 new G4Element(name = "Phosphorus", symbol = "P", z = 15.0, a = 30.973976 * g / mole);
0141 G4Element* elS = new G4Element(name = "Sulfur", symbol = "S", z = 16.0, a = 32.065 * g / mole);
0142 G4Element* elCl =
0143 new G4Element(name = "Chlorine", symbol = "Cl", z = 17.0, a = 35.453 * g / mole);
0144 G4Element* elK =
0145 new G4Element(name = "Potassium", symbol = "K", z = 19.0, a = 30.0983 * g / mole);
0146
0147 G4Element* elFe = new G4Element(name = "Iron", symbol = "Fe", z = 26, a = 56.845 * g / mole);
0148
0149 G4Element* elCa = new G4Element(name = "Calcium", symbol = "Ca", z = 20.0, a = 40.078 * g / mole);
0150
0151 G4Element* elZn = new G4Element(name = "Zinc", symbol = "Zn", z = 30.0, a = 65.382 * g / mole);
0152
0153
0154 G4int numberofElements;
0155
0156
0157 fAir = new G4Material("Air", 1.290 * mg / cm3, numberofElements = 2);
0158 fAir->AddElement(elN, 0.7);
0159 fAir->AddElement(elO, 0.3);
0160
0161
0162 G4Material* softTissue = new G4Material("SoftTissue", 1.00 * g / cm3, numberofElements = 13);
0163 softTissue->AddElement(elH, 10.4472 * perCent);
0164 softTissue->AddElement(elC, 23.219 * perCent);
0165 softTissue->AddElement(elN, 2.488 * perCent);
0166 softTissue->AddElement(elO, 63.0238 * perCent);
0167 softTissue->AddElement(elNa, 0.113 * perCent);
0168 softTissue->AddElement(elMg, 0.0113 * perCent);
0169 softTissue->AddElement(elP, 0.113 * perCent);
0170 softTissue->AddElement(elS, 0.199 * perCent);
0171 softTissue->AddElement(elCl, 0.134 * perCent);
0172 softTissue->AddElement(elK, 0.199 * perCent);
0173 softTissue->AddElement(elCa, 0.023 * perCent);
0174 softTissue->AddElement(elFe, 0.005 * perCent);
0175 softTissue->AddElement(elZn, 0.003 * perCent);
0176
0177
0178 G4Material* lunginhale =
0179 new G4Material("LungInhale", density = 0.217 * g / cm3, numberofElements = 9);
0180 lunginhale->AddElement(elH, 0.103);
0181 lunginhale->AddElement(elC, 0.105);
0182 lunginhale->AddElement(elN, 0.031);
0183 lunginhale->AddElement(elO, 0.749);
0184 lunginhale->AddElement(elNa, 0.002);
0185 lunginhale->AddElement(elP, 0.002);
0186 lunginhale->AddElement(elS, 0.003);
0187 lunginhale->AddElement(elCl, 0.002);
0188 lunginhale->AddElement(elK, 0.003);
0189
0190
0191 G4Material* lungexhale =
0192 new G4Material("LungExhale", density = 0.508 * g / cm3, numberofElements = 9);
0193 lungexhale->AddElement(elH, 0.103);
0194 lungexhale->AddElement(elC, 0.105);
0195 lungexhale->AddElement(elN, 0.031);
0196 lungexhale->AddElement(elO, 0.749);
0197 lungexhale->AddElement(elNa, 0.002);
0198 lungexhale->AddElement(elP, 0.002);
0199 lungexhale->AddElement(elS, 0.003);
0200 lungexhale->AddElement(elCl, 0.002);
0201 lungexhale->AddElement(elK, 0.003);
0202
0203
0204 G4Material* adiposeTissue =
0205 new G4Material("AdiposeTissue", density = 0.967 * g / cm3, numberofElements = 7);
0206 adiposeTissue->AddElement(elH, 0.114);
0207 adiposeTissue->AddElement(elC, 0.598);
0208 adiposeTissue->AddElement(elN, 0.007);
0209 adiposeTissue->AddElement(elO, 0.278);
0210 adiposeTissue->AddElement(elNa, 0.001);
0211 adiposeTissue->AddElement(elS, 0.001);
0212 adiposeTissue->AddElement(elCl, 0.001);
0213
0214
0215 G4Material* brainTissue = new G4Material("BrainTissue", 1.03 * g / cm3, numberofElements = 13);
0216 brainTissue->AddElement(elH, 11.0667 * perCent);
0217 brainTissue->AddElement(elC, 12.542 * perCent);
0218 brainTissue->AddElement(elN, 1.328 * perCent);
0219 brainTissue->AddElement(elO, 73.7723 * perCent);
0220 brainTissue->AddElement(elNa, 0.1840 * perCent);
0221 brainTissue->AddElement(elMg, 0.015 * perCent);
0222 brainTissue->AddElement(elP, 0.356 * perCent);
0223 brainTissue->AddElement(elS, 0.177 * perCent);
0224 brainTissue->AddElement(elCl, 0.236 * perCent);
0225 brainTissue->AddElement(elK, 0.31 * perCent);
0226 brainTissue->AddElement(elCa, 0.009 * perCent);
0227 brainTissue->AddElement(elFe, 0.005 * perCent);
0228 brainTissue->AddElement(elZn, 0.001 * perCent);
0229
0230
0231 G4Material* breast = new G4Material("Breast", density = 0.990 * g / cm3, numberofElements = 8);
0232 breast->AddElement(elH, 0.109);
0233 breast->AddElement(elC, 0.506);
0234 breast->AddElement(elN, 0.023);
0235 breast->AddElement(elO, 0.358);
0236 breast->AddElement(elNa, 0.001);
0237 breast->AddElement(elP, 0.001);
0238 breast->AddElement(elS, 0.001);
0239 breast->AddElement(elCl, 0.001);
0240
0241
0242 G4Material* spinalDisc = new G4Material("SpinalDisc", 1.10 * g / cm3, numberofElements = 8);
0243 spinalDisc->AddElement(elH, 9.60 * perCent);
0244 spinalDisc->AddElement(elC, 9.90 * perCent);
0245 spinalDisc->AddElement(elN, 2.20 * perCent);
0246 spinalDisc->AddElement(elO, 74.40 * perCent);
0247 spinalDisc->AddElement(elNa, 0.50 * perCent);
0248 spinalDisc->AddElement(elP, 2.20 * perCent);
0249 spinalDisc->AddElement(elS, 0.90 * perCent);
0250 spinalDisc->AddElement(elCl, 0.30 * perCent);
0251
0252
0253 G4Material* water = new G4Material("Water", density = 1.0 * g / cm3, numberofElements = 2);
0254 water->AddElement(elH, 0.112);
0255 water->AddElement(elO, 0.888);
0256
0257
0258 G4Material* muscle = new G4Material("Muscle", density = 1.061 * g / cm3, numberofElements = 9);
0259 muscle->AddElement(elH, 0.102);
0260 muscle->AddElement(elC, 0.143);
0261 muscle->AddElement(elN, 0.034);
0262 muscle->AddElement(elO, 0.710);
0263 muscle->AddElement(elNa, 0.001);
0264 muscle->AddElement(elP, 0.002);
0265 muscle->AddElement(elS, 0.003);
0266 muscle->AddElement(elCl, 0.001);
0267 muscle->AddElement(elK, 0.004);
0268
0269
0270 G4Material* liver = new G4Material("Liver", density = 1.071 * g / cm3, numberofElements = 9);
0271 liver->AddElement(elH, 0.102);
0272 liver->AddElement(elC, 0.139);
0273 liver->AddElement(elN, 0.030);
0274 liver->AddElement(elO, 0.716);
0275 liver->AddElement(elNa, 0.002);
0276 liver->AddElement(elP, 0.003);
0277 liver->AddElement(elS, 0.003);
0278 liver->AddElement(elCl, 0.002);
0279 liver->AddElement(elK, 0.003);
0280
0281
0282 G4Material* toothDentin = new G4Material("ToothDentin", 2.14 * g / cm3, numberofElements = 10);
0283 toothDentin->AddElement(elH, 2.67 * perCent);
0284 toothDentin->AddElement(elC, 12.77 * perCent);
0285 toothDentin->AddElement(elN, 4.27 * perCent);
0286 toothDentin->AddElement(elO, 40.40 * perCent);
0287 toothDentin->AddElement(elNa, 0.65 * perCent);
0288 toothDentin->AddElement(elMg, 0.59 * perCent);
0289 toothDentin->AddElement(elP, 11.86 * perCent);
0290 toothDentin->AddElement(elCl, 0.04 * perCent);
0291 toothDentin->AddElement(elCa, 26.74 * perCent);
0292 toothDentin->AddElement(elZn, 0.01 * perCent);
0293
0294
0295 G4Material* trabecularBone =
0296 new G4Material("TrabecularBone", density = 1.159 * g / cm3, numberofElements = 12);
0297 trabecularBone->AddElement(elH, 0.085);
0298 trabecularBone->AddElement(elC, 0.404);
0299 trabecularBone->AddElement(elN, 0.058);
0300 trabecularBone->AddElement(elO, 0.367);
0301 trabecularBone->AddElement(elNa, 0.001);
0302 trabecularBone->AddElement(elMg, 0.001);
0303 trabecularBone->AddElement(elP, 0.034);
0304 trabecularBone->AddElement(elS, 0.002);
0305 trabecularBone->AddElement(elCl, 0.002);
0306 trabecularBone->AddElement(elK, 0.001);
0307 trabecularBone->AddElement(elCa, 0.044);
0308 trabecularBone->AddElement(elFe, 0.001);
0309
0310
0311
0312 G4Material* trabecularBone_head =
0313 new G4Material("TrabecularBone_HEAD", 1.18 * g / cm3, numberofElements = 12);
0314 trabecularBone_head->AddElement(elH, 8.50 * perCent);
0315 trabecularBone_head->AddElement(elC, 40.40 * perCent);
0316 trabecularBone_head->AddElement(elN, 2.80 * perCent);
0317 trabecularBone_head->AddElement(elO, 36.70 * perCent);
0318 trabecularBone_head->AddElement(elNa, 0.10 * perCent);
0319 trabecularBone_head->AddElement(elMg, 0.10 * perCent);
0320 trabecularBone_head->AddElement(elP, 3.40 * perCent);
0321 trabecularBone_head->AddElement(elS, 0.20 * perCent);
0322 trabecularBone_head->AddElement(elCl, 0.20 * perCent);
0323 trabecularBone_head->AddElement(elK, 0.10 * perCent);
0324 trabecularBone_head->AddElement(elCa, 7.40 * perCent);
0325 trabecularBone_head->AddElement(elFe, 0.10 * perCent);
0326
0327
0328 G4Material* denseBone =
0329 new G4Material("DenseBone", density = 1.575 * g / cm3, numberofElements = 11);
0330 denseBone->AddElement(elH, 0.056);
0331 denseBone->AddElement(elC, 0.235);
0332 denseBone->AddElement(elN, 0.050);
0333 denseBone->AddElement(elO, 0.434);
0334 denseBone->AddElement(elNa, 0.001);
0335 denseBone->AddElement(elMg, 0.001);
0336 denseBone->AddElement(elP, 0.072);
0337 denseBone->AddElement(elS, 0.003);
0338 denseBone->AddElement(elCl, 0.001);
0339 denseBone->AddElement(elK, 0.001);
0340 denseBone->AddElement(elCa, 0.146);
0341
0342
0343 G4Material* corticalBone = new G4Material("CorticalBone", 1.85 * g / cm3, numberofElements = 9);
0344 corticalBone->AddElement(elH, 4.7234 * perCent);
0345 corticalBone->AddElement(elC, 14.4330 * perCent);
0346 corticalBone->AddElement(elN, 4.199 * perCent);
0347 corticalBone->AddElement(elO, 44.6096 * perCent);
0348 corticalBone->AddElement(elMg, 0.22 * perCent);
0349 corticalBone->AddElement(elP, 10.497 * perCent);
0350 corticalBone->AddElement(elS, 0.315 * perCent);
0351 corticalBone->AddElement(elCa, 20.993 * perCent);
0352 corticalBone->AddElement(elZn, 0.01 * perCent);
0353
0354
0355 G4Material* toothEnamel = new G4Material("ToothEnamel", 2.89 * g / cm3, numberofElements = 10);
0356 toothEnamel->AddElement(elH, 0.95 * perCent);
0357 toothEnamel->AddElement(elC, 1.11 * perCent);
0358 toothEnamel->AddElement(elN, 0.23 * perCent);
0359 toothEnamel->AddElement(elO, 41.66 * perCent);
0360 toothEnamel->AddElement(elNa, 0.79 * perCent);
0361 toothEnamel->AddElement(elMg, 0.23 * perCent);
0362 toothEnamel->AddElement(elP, 18.71 * perCent);
0363 toothEnamel->AddElement(elCl, 0.34 * perCent);
0364 toothEnamel->AddElement(elCa, 35.97 * perCent);
0365 toothEnamel->AddElement(elZn, 0.02 * perCent);
0366
0367 #ifdef DICOM_USE_HEAD
0368
0369 fOriginalMaterials.push_back(fAir);
0370 fOriginalMaterials.push_back(softTissue);
0371 fOriginalMaterials.push_back(brainTissue);
0372 fOriginalMaterials.push_back(spinalDisc);
0373 fOriginalMaterials.push_back(trabecularBone_head);
0374 fOriginalMaterials.push_back(toothDentin);
0375 fOriginalMaterials.push_back(corticalBone);
0376 fOriginalMaterials.push_back(toothEnamel);
0377 G4cout << "The materials of the DICOM Head have been used" << G4endl;
0378 #else
0379 fOriginalMaterials.push_back(fAir);
0380 fOriginalMaterials.push_back(lunginhale);
0381 fOriginalMaterials.push_back(lungexhale);
0382 fOriginalMaterials.push_back(adiposeTissue);
0383 fOriginalMaterials.push_back(breast);
0384 fOriginalMaterials.push_back(water);
0385 fOriginalMaterials.push_back(muscle);
0386 fOriginalMaterials.push_back(liver);
0387 fOriginalMaterials.push_back(trabecularBone);
0388 fOriginalMaterials.push_back(denseBone);
0389 G4cout << "Default materials of the DICOM Extended examples have been used" << G4endl;
0390 #endif
0391 }
0392
0393
0394 void DicomDetectorConstruction::ReadPhantomDataNew()
0395 {
0396 #ifdef G4_DCMTK
0397 G4String fileName = DicomFileMgr::GetInstance()->GetFileOutName();
0398
0399 std::ifstream fin(fileName);
0400 std::vector<G4String> wl;
0401 G4int nMaterials;
0402 fin >> nMaterials;
0403 G4String mateName;
0404 G4int nmate;
0405 for (G4int ii = 0; ii < nMaterials; ++ii) {
0406 fin >> nmate;
0407 fin >> mateName;
0408 if (mateName[0] == '"' && mateName[mateName.length() - 1] == '"') {
0409 mateName = mateName.substr(1, mateName.length() - 2);
0410 }
0411 G4cout << "GmReadPhantomG4Geometry::ReadPhantomData reading nmate " << ii << " = " << nmate
0412 << " mate " << mateName << G4endl;
0413 if (ii != nmate)
0414 G4Exception("GmReadPhantomG4Geometry::ReadPhantomData", "Wrong argument",
0415 FatalErrorInArgument,
0416 "Material number should be in increasing order:wrong material number");
0417
0418 G4Material* mate = 0;
0419 const G4MaterialTable* matTab = G4Material::GetMaterialTable();
0420 for (auto matite = matTab->cbegin(); matite != matTab->cend(); ++matite) {
0421 if ((*matite)->GetName() == mateName) {
0422 mate = *matite;
0423 }
0424 }
0425 if (mate == 0) {
0426 mate = G4NistManager::Instance()->FindOrBuildMaterial(mateName);
0427 }
0428 if (!mate)
0429 G4Exception("GmReadPhantomG4Geometry::ReadPhantomData", "Wrong argument",
0430 FatalErrorInArgument, ("Material not found" + mateName).c_str());
0431 fPhantomMaterialsOriginal[nmate] = mate;
0432 }
0433
0434 fin >> fNoVoxelsX >> fNoVoxelsY >> fNoVoxelsZ;
0435 G4cout << "GmReadPhantomG4Geometry::ReadPhantomData fNoVoxels X/Y/Z " << fNoVoxelsX << " "
0436 << fNoVoxelsY << " " << fNoVoxelsZ << G4endl;
0437 fin >> fMinX >> fMaxX;
0438 fin >> fMinY >> fMaxY;
0439 fin >> fMinZ >> fMaxZ;
0440 fVoxelHalfDimX = (fMaxX - fMinX) / fNoVoxelsX / 2.;
0441 fVoxelHalfDimY = (fMaxY - fMinY) / fNoVoxelsY / 2.;
0442 fVoxelHalfDimZ = (fMaxZ - fMinZ) / fNoVoxelsZ / 2.;
0443 # ifdef G4VERBOSE
0444 G4cout << " Extension in X " << fMinX << " " << fMaxX << G4endl << " Extension in Y " << fMinY
0445 << " " << fMaxY << G4endl << " Extension in Z " << fMinZ << " " << fMaxZ << G4endl;
0446 # endif
0447
0448 fMateIDs = new size_t[fNoVoxelsX * fNoVoxelsY * fNoVoxelsZ];
0449 for (G4int iz = 0; iz < fNoVoxelsZ; ++iz) {
0450 for (G4int iy = 0; iy < fNoVoxelsY; ++iy) {
0451 for (G4int ix = 0; ix < fNoVoxelsX; ++ix) {
0452 G4int mateID;
0453 fin >> mateID;
0454 G4int nnew = ix + (iy)*fNoVoxelsX + (iz)*fNoVoxelsX * fNoVoxelsY;
0455 if (mateID < 0 || mateID >= nMaterials) {
0456 G4Exception("GmReadPhantomG4Geometry::ReadPhantomData", "Wrong index in phantom file",
0457 FatalException,
0458 G4String("It should be between 0 and "
0459 + G4UIcommand::ConvertToString(nMaterials - 1) + ", while it is "
0460 + G4UIcommand::ConvertToString(mateID))
0461 .c_str());
0462 }
0463 fMateIDs[nnew] = mateID;
0464 }
0465 }
0466 }
0467
0468 ReadVoxelDensities(fin);
0469
0470 fin.close();
0471 #endif
0472 }
0473
0474
0475 void DicomDetectorConstruction::ReadVoxelDensities(std::ifstream& fin)
0476 {
0477 G4String stemp;
0478 std::map<G4int, std::pair<G4double, G4double>> densiMinMax;
0479 std::map<G4int, std::pair<G4double, G4double>>::iterator mpite;
0480 for (G4int ii = 0; ii < G4int(fPhantomMaterialsOriginal.size()); ++ii) {
0481 densiMinMax[ii] = std::pair<G4double, G4double>(DBL_MAX, -DBL_MAX);
0482 }
0483
0484 char* part = std::getenv("DICOM_CHANGE_MATERIAL_DENSITY");
0485 G4double densityDiff = -1.;
0486 if (part) densityDiff = G4UIcommand::ConvertToDouble(part);
0487
0488 std::map<G4int, G4double> densityDiffs;
0489 for (G4int ii = 0; ii < G4int(fPhantomMaterialsOriginal.size()); ++ii) {
0490 densityDiffs[ii] = densityDiff;
0491 }
0492
0493
0494
0495 std::map<std::pair<G4Material*, G4int>, matInfo*> newMateDens;
0496
0497
0498 G4double dens;
0499 for (G4int iz = 0; iz < fNoVoxelsZ; ++iz) {
0500 for (G4int iy = 0; iy < fNoVoxelsY; ++iy) {
0501 for (G4int ix = 0; ix < fNoVoxelsX; ++ix) {
0502 fin >> dens;
0503 G4int copyNo = ix + (iy)*fNoVoxelsX + (iz)*fNoVoxelsX * fNoVoxelsY;
0504
0505 if (densityDiff != -1.) continue;
0506
0507
0508 mpite = densiMinMax.find(G4int(fMateIDs[copyNo]));
0509 if (dens < (*mpite).second.first) (*mpite).second.first = dens;
0510 if (dens > (*mpite).second.second) (*mpite).second.second = dens;
0511
0512 G4int mateID = G4int(fMateIDs[copyNo]);
0513 std::map<G4int, G4Material*>::const_iterator imite = fPhantomMaterialsOriginal.find(mateID);
0514
0515
0516 if (std::fabs(dens - (*imite).second->GetDensity() / CLHEP::g * CLHEP::cm3) < 1.e-9)
0517 continue;
0518
0519
0520 G4int densityBin = (G4int(dens / densityDiffs[mateID]));
0521
0522 G4String mateName = (*imite).second->GetName() + G4UIcommand::ConvertToString(densityBin);
0523
0524 std::pair<G4Material*, G4int> matdens((*imite).second, densityBin);
0525
0526 auto mppite = newMateDens.find(matdens);
0527 if (mppite != newMateDens.cend()) {
0528 matInfo* mi = (*mppite).second;
0529 mi->fSumdens += dens;
0530 mi->fNvoxels++;
0531 fMateIDs[copyNo] = fPhantomMaterialsOriginal.size() - 1 + mi->fId;
0532 }
0533 else {
0534 matInfo* mi = new matInfo;
0535 mi->fSumdens = dens;
0536 mi->fNvoxels = 1;
0537 mi->fId = G4int(newMateDens.size() + 1);
0538 newMateDens[matdens] = mi;
0539 fMateIDs[copyNo] = fPhantomMaterialsOriginal.size() - 1 + mi->fId;
0540 }
0541 }
0542 }
0543 }
0544
0545 if (densityDiff != -1.) {
0546 for (mpite = densiMinMax.begin(); mpite != densiMinMax.end(); ++mpite) {
0547 #ifdef G4VERBOSE
0548 G4cout << "DicomDetectorConstruction::ReadVoxelDensities"
0549 << " ORIG MATERIALS DENSITY " << (*mpite).first << " MIN " << (*mpite).second.first
0550 << " MAX " << (*mpite).second.second << G4endl;
0551 #endif
0552 }
0553 }
0554
0555
0556
0557 for (auto mimite = fPhantomMaterialsOriginal.cbegin(); mimite != fPhantomMaterialsOriginal.cend();
0558 ++mimite)
0559 {
0560 fMaterials.push_back((*mimite).second);
0561 }
0562
0563
0564 for (auto mppite = newMateDens.cbegin(); mppite != newMateDens.cend(); ++mppite) {
0565 G4double averdens = (*mppite).second->fSumdens / (*mppite).second->fNvoxels;
0566 G4double saverdens = G4int(1000.001 * averdens) / 1000.;
0567 #ifndef G4VERBOSE
0568 G4cout << "DicomDetectorConstruction::ReadVoxelDensities AVER DENS " << averdens << " -> "
0569 << saverdens << " -> " << G4int(1000 * averdens) << " " << G4int(1000 * averdens) / 1000
0570 << " " << G4int(1000 * averdens) / 1000. << G4endl;
0571 #endif
0572
0573 G4String mateName =
0574 ((*mppite).first).first->GetName() + "_" + G4UIcommand::ConvertToString(saverdens);
0575 fMaterials.push_back(
0576 BuildMaterialWithChangingDensity((*mppite).first.first, G4float(averdens), mateName));
0577 }
0578 }
0579
0580
0581 void DicomDetectorConstruction::ReadPhantomData()
0582 {
0583 G4String dataFile = DicomHandler::GetDicomDataFile();
0584 std::ifstream finDF(dataFile.c_str());
0585 G4String fname;
0586
0587 if (finDF.good() != 1) {
0588 G4String descript = "Problem reading data file: " + dataFile;
0589 G4Exception(" DicomDetectorConstruction::ReadPhantomData", " ", FatalException, descript);
0590 }
0591
0592 G4int compression;
0593 finDF >> compression;
0594 finDF >> fNoFiles;
0595
0596 for (G4int i = 0; i < fNoFiles; ++i) {
0597 finDF >> fname;
0598
0599
0600 fname += ".g4dcm";
0601
0602 ReadPhantomDataFile(fname);
0603 }
0604
0605
0606 MergeZSliceHeaders();
0607 finDF.close();
0608 }
0609
0610
0611 void DicomDetectorConstruction::ReadPhantomDataFile(const G4String& fname)
0612 {
0613 G4cout << " DicomDetectorConstruction::ReadPhantomDataFile opening file " << fname
0614 << G4endl;
0615
0616 #ifdef G4VERBOSE
0617 G4cout << " DicomDetectorConstruction::ReadPhantomDataFile opening file " << fname << G4endl;
0618 #endif
0619
0620 std::ifstream fin(fname.c_str(), std::ios_base::in);
0621 if (!fin.is_open()) {
0622 G4Exception("DicomDetectorConstruction::ReadPhantomDataFile", "", FatalErrorInArgument,
0623 G4String("File not found " + fname).c_str());
0624 }
0625
0626
0627 char* part = std::getenv("DICOM_CHANGE_MATERIAL_DENSITY");
0628 G4double densityDiff = -1.;
0629 if (part) densityDiff = G4UIcommand::ConvertToDouble(part);
0630 if (densityDiff != -1.) {
0631 for (unsigned int ii = 0; ii < fOriginalMaterials.size(); ++ii) {
0632 fDensityDiffs[ii] = densityDiff;
0633
0634 }
0635 }
0636 else {
0637 if (fMaterials.size() == 0) {
0638 for (unsigned int ii = 0; ii < fOriginalMaterials.size(); ++ii) {
0639 fMaterials.push_back(fOriginalMaterials[ii]);
0640 }
0641 }
0642 }
0643
0644
0645 DicomPhantomZSliceHeader* sliceHeader = new DicomPhantomZSliceHeader(fin);
0646 fZSliceHeaders.push_back(sliceHeader);
0647
0648
0649 G4int nVoxels = sliceHeader->GetNoVoxels();
0650
0651
0652 if (fZSliceHeaders.size() == 1) {
0653
0654 fMateIDs = new size_t[fNoFiles * nVoxels];
0655 }
0656
0657 unsigned int mateID;
0658
0659 G4int voxelCopyNo = G4int((fZSliceHeaders.size() - 1) * nVoxels);
0660 for (G4int ii = 0; ii < nVoxels; ++ii, voxelCopyNo++) {
0661 fin >> mateID;
0662 fMateIDs[voxelCopyNo] = mateID;
0663 }
0664
0665
0666
0667
0668 G4double density;
0669
0670 voxelCopyNo = G4int((fZSliceHeaders.size() - 1) * nVoxels);
0671 for (G4int ii = 0; ii < nVoxels; ++ii, voxelCopyNo++) {
0672 fin >> density;
0673
0674
0675 mateID = unsigned(fMateIDs[voxelCopyNo]);
0676 G4Material* mateOrig = fOriginalMaterials[mateID];
0677
0678
0679
0680 G4String newMateName = mateOrig->GetName();
0681 G4float densityBin = 0.;
0682 if (densityDiff != -1.) {
0683 densityBin = G4float(fDensityDiffs[mateID]) * (G4int(density / fDensityDiffs[mateID]) + 0.5);
0684
0685 newMateName += G4UIcommand::ConvertToString(densityBin);
0686 }
0687
0688
0689
0690 unsigned int im;
0691 for (im = 0; im < fMaterials.size(); ++im) {
0692 if (fMaterials[im]->GetName() == newMateName) {
0693 break;
0694 }
0695 }
0696
0697 if (im != fMaterials.size()) {
0698 fMateIDs[voxelCopyNo] = im;
0699
0700 }
0701 else {
0702 if (densityDiff != -1.) {
0703 fMaterials.push_back(BuildMaterialWithChangingDensity(mateOrig, densityBin, newMateName));
0704 fMateIDs[voxelCopyNo] = fMaterials.size() - 1;
0705 }
0706 else {
0707 G4cerr << " im " << im << " < " << fMaterials.size() << " name " << newMateName << G4endl;
0708 G4Exception("DicomDetectorConstruction::ReadPhantomDataFile", "", FatalErrorInArgument,
0709 "Wrong index in material");
0710 }
0711 }
0712 }
0713 }
0714
0715
0716 void DicomDetectorConstruction::MergeZSliceHeaders()
0717 {
0718
0719 fZSliceHeaderMerged = new DicomPhantomZSliceHeader(*fZSliceHeaders[0]);
0720 for (unsigned int ii = 1; ii < fZSliceHeaders.size(); ++ii) {
0721 *fZSliceHeaderMerged += *fZSliceHeaders[ii];
0722 }
0723 }
0724
0725
0726 G4Material* DicomDetectorConstruction::BuildMaterialWithChangingDensity(const G4Material* origMate,
0727 G4float density,
0728 G4String newMateName)
0729 {
0730
0731 G4int nelem = G4int(origMate->GetNumberOfElements());
0732 G4Material* mate =
0733 new G4Material(newMateName, density * g / cm3, nelem, kStateUndefined, STP_Temperature);
0734
0735 for (G4int ii = 0; ii < nelem; ++ii) {
0736 G4double frac = origMate->GetFractionVector()[ii];
0737 G4Element* elem = const_cast<G4Element*>(origMate->GetElement(ii));
0738 mate->AddElement(elem, frac);
0739 }
0740
0741 return mate;
0742 }
0743
0744
0745 void DicomDetectorConstruction::ConstructPhantomContainer()
0746 {
0747
0748 fNoVoxelsX = fZSliceHeaderMerged->GetNoVoxelsX();
0749 fNoVoxelsY = fZSliceHeaderMerged->GetNoVoxelsY();
0750 fNoVoxelsZ = fZSliceHeaderMerged->GetNoVoxelsZ();
0751
0752 fVoxelHalfDimX = fZSliceHeaderMerged->GetVoxelHalfX();
0753 fVoxelHalfDimY = fZSliceHeaderMerged->GetVoxelHalfY();
0754 fVoxelHalfDimZ = fZSliceHeaderMerged->GetVoxelHalfZ();
0755 #ifdef G4VERBOSE
0756 G4cout << " fNoVoxelsX " << fNoVoxelsX << " fVoxelHalfDimX " << fVoxelHalfDimX << G4endl;
0757 G4cout << " fNoVoxelsY " << fNoVoxelsY << " fVoxelHalfDimY " << fVoxelHalfDimY << G4endl;
0758 G4cout << " fNoVoxelsZ " << fNoVoxelsZ << " fVoxelHalfDimZ " << fVoxelHalfDimZ << G4endl;
0759 G4cout << " totalPixels " << fNoVoxelsX * fNoVoxelsY * fNoVoxelsZ << G4endl;
0760 #endif
0761
0762
0763 fContainer_solid = new G4Box("phantomContainer", fNoVoxelsX * fVoxelHalfDimX,
0764 fNoVoxelsY * fVoxelHalfDimY, fNoVoxelsZ * fVoxelHalfDimZ);
0765 fContainer_logic =
0766 new G4LogicalVolume(fContainer_solid,
0767
0768 fMaterials[0], "phantomContainer", 0, 0, 0);
0769
0770 G4double fOffsetX = (fZSliceHeaderMerged->GetMaxX() + fZSliceHeaderMerged->GetMinX()) / 2.;
0771 G4double fOffsetY = (fZSliceHeaderMerged->GetMaxY() + fZSliceHeaderMerged->GetMinY()) / 2.;
0772 G4double fOffsetZ = (fZSliceHeaderMerged->GetMaxZ() + fZSliceHeaderMerged->GetMinZ()) / 2.;
0773 G4ThreeVector posCentreVoxels(fOffsetX, fOffsetY, fOffsetZ);
0774 #ifdef G4VERBOSE
0775 G4cout << " placing voxel container volume at " << posCentreVoxels << G4endl;
0776 #endif
0777 fContainer_phys = new G4PVPlacement(0,
0778 posCentreVoxels,
0779 fContainer_logic,
0780 "phantomContainer",
0781 fWorld_logic,
0782 false,
0783 1);
0784 }
0785
0786
0787 void DicomDetectorConstruction::ConstructPhantomContainerNew()
0788 {
0789 #ifdef G4_DCMTK
0790
0791 # ifdef G4VERBOSE
0792 G4cout << " fNoVoxelsX " << fNoVoxelsX << " fVoxelHalfDimX " << fVoxelHalfDimX << G4endl;
0793 G4cout << " fNoVoxelsY " << fNoVoxelsY << " fVoxelHalfDimY " << fVoxelHalfDimY << G4endl;
0794 G4cout << " fNoVoxelsZ " << fNoVoxelsZ << " fVoxelHalfDimZ " << fVoxelHalfDimZ << G4endl;
0795 G4cout << " totalPixels " << fNoVoxelsX * fNoVoxelsY * fNoVoxelsZ << G4endl;
0796 # endif
0797
0798
0799 fContainer_solid = new G4Box("phantomContainer", fNoVoxelsX * fVoxelHalfDimX,
0800 fNoVoxelsY * fVoxelHalfDimY, fNoVoxelsZ * fVoxelHalfDimZ);
0801 fContainer_logic =
0802 new G4LogicalVolume(fContainer_solid,
0803
0804 fMaterials[0], "phantomContainer", 0, 0, 0);
0805
0806 G4ThreeVector posCentreVoxels((fMinX + fMaxX) / 2., (fMinY + fMaxY) / 2., (fMinZ + fMaxZ) / 2.);
0807 # ifdef G4VERBOSE
0808 G4cout << " placing voxel container volume at " << posCentreVoxels << G4endl;
0809 # endif
0810 fContainer_phys = new G4PVPlacement(0,
0811 posCentreVoxels,
0812 fContainer_logic,
0813 "phantomContainer",
0814 fWorld_logic,
0815 false,
0816 1);
0817 #endif
0818 }
0819
0820 #include "G4MultiFunctionalDetector.hh"
0821 #include "G4PSDoseDeposit.hh"
0822 #include "G4PSDoseDeposit3D.hh"
0823 #include "G4SDManager.hh"
0824
0825
0826 void DicomDetectorConstruction::SetScorer(G4LogicalVolume* voxel_logic)
0827 {
0828 #ifdef G4VERBOSE
0829 G4cout << "\t SET SCORER : " << voxel_logic->GetName() << G4endl;
0830 #endif
0831
0832 fScorers.insert(voxel_logic);
0833 }
0834
0835
0836
0837 void DicomDetectorConstruction::ConstructSDandField()
0838 {
0839 #ifdef G4VERBOSE
0840 G4cout << "\t CONSTRUCT SD AND FIELD" << G4endl;
0841 #endif
0842
0843
0844
0845
0846
0847
0848
0849 G4String concreteSDname = "phantomSD";
0850 std::vector<G4String> scorer_names;
0851 scorer_names.push_back(concreteSDname);
0852
0853
0854
0855
0856
0857
0858 G4MultiFunctionalDetector* MFDet = new G4MultiFunctionalDetector(concreteSDname);
0859 G4SDManager::GetSDMpointer()->AddNewDetector(MFDet);
0860 char* nest = std::getenv("DICOM_NESTED_PARAM");
0861 if (nest && G4String(nest) == "1") {
0862 G4VPrimitiveScorer* dosedep = new G4PSDoseDeposit3D(
0863 "DoseDeposit", fNoVoxelsZ, fNoVoxelsY, fNoVoxelsX, 0, 2, 1);
0864
0865 MFDet->RegisterPrimitive(dosedep);
0866 }
0867 else {
0868 G4VPrimitiveScorer* dosedep = new G4PSDoseDeposit("DoseDeposit");
0869 MFDet->RegisterPrimitive(dosedep);
0870 }
0871
0872 for (auto ite = fScorers.cbegin(); ite != fScorers.cend(); ++ite) {
0873 SetSensitiveDetector(*ite, MFDet);
0874 }
0875 }