File indexing completed on 2025-02-23 09:21:45
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 "DicomPartialDetectorConstruction.hh"
0032
0033 #include "G4Box.hh"
0034 #include "G4Colour.hh"
0035 #include "G4Element.hh"
0036 #include "G4LogicalVolume.hh"
0037 #include "G4Material.hh"
0038 #include "G4NistManager.hh"
0039 #include "G4PVParameterised.hh"
0040 #include "G4PVPlacement.hh"
0041 #include "G4PartialPhantomParameterisation.hh"
0042 #include "G4SystemOfUnits.hh"
0043 #include "G4Tubs.hh"
0044 #include "G4UIcommand.hh"
0045 #include "G4VPhysicalVolume.hh"
0046 #include "G4VisAttributes.hh"
0047 #include "G4ios.hh"
0048 #include "G4tgbMaterialMgr.hh"
0049 #include "G4tgbVolumeMgr.hh"
0050 #include "G4tgrMessenger.hh"
0051 #include "globals.hh"
0052
0053
0054 DicomPartialDetectorConstruction::DicomPartialDetectorConstruction()
0055 : DicomDetectorConstruction(),
0056 fPartialPhantomParam(0),
0057 fNoVoxels(0),
0058 fDimX(0),
0059 fDimY(0),
0060 fDimZ(0),
0061 fOffsetX(0),
0062 fOffsetY(0),
0063 fOffsetZ(0)
0064 {}
0065
0066
0067 DicomPartialDetectorConstruction::~DicomPartialDetectorConstruction() {}
0068
0069
0070 G4VPhysicalVolume* DicomPartialDetectorConstruction::Construct()
0071 {
0072 InitialisationOfMaterials();
0073
0074
0075 G4double worldXDimension = 1. * m;
0076 G4double worldYDimension = 1. * m;
0077 G4double worldZDimension = 1. * m;
0078
0079 G4Box* world_box = new G4Box("WorldSolid", worldXDimension, worldYDimension, worldZDimension);
0080
0081 fWorld_logic = new G4LogicalVolume(world_box, fAir, "WorldLogical", 0, 0, 0);
0082
0083 G4VPhysicalVolume* world_phys =
0084 new G4PVPlacement(0, G4ThreeVector(0, 0, 0), "World", fWorld_logic, 0, false, 0);
0085
0086 ReadPhantomData();
0087
0088 ConstructPhantomContainer();
0089 ConstructPhantom();
0090
0091 return world_phys;
0092 }
0093
0094
0095 void DicomPartialDetectorConstruction::ReadPhantomData()
0096 {
0097 G4String dataFile = "Data.dat";
0098 std::ifstream finDF(dataFile.c_str());
0099 G4String fname;
0100 if (finDF.good() != 1) {
0101 G4Exception(" DicomPartialDetectorConstruction::ReadPhantomData", "", FatalErrorInArgument,
0102 " Problem reading data file: Data.dat");
0103 }
0104
0105 G4int compression;
0106 finDF >> compression;
0107
0108 G4int numFiles;
0109 finDF >> numFiles;
0110 if (numFiles != 1) {
0111 G4Exception("DicomPartialDetectorConstruction::ReadPhantomData", "", FatalErrorInArgument,
0112 "More than 1 DICOM file is not supported");
0113 }
0114 for (G4int i = 0; i < numFiles; i++) {
0115 finDF >> fname;
0116
0117 fname += ".g4pdcm";
0118 ReadPhantomDataFile(fname);
0119 }
0120
0121 finDF.close();
0122 }
0123
0124
0125 void DicomPartialDetectorConstruction::ReadPhantomDataFile(const G4String& fname)
0126 {
0127
0128 #ifdef G4VERBOSE
0129 G4cout << " DicomDetectorConstruction::ReadPhantomDataFile opening file " << fname << G4endl;
0130 #endif
0131 std::ifstream fin(fname.c_str(), std::ios_base::in);
0132 if (!fin.is_open()) {
0133 G4Exception("DicomPartialDetectorConstruction::ReadPhantomDataFile", "", FatalException,
0134 G4String("File not found " + fname).c_str());
0135 }
0136 G4int nMaterials;
0137 fin >> nMaterials;
0138 G4String stemp;
0139 G4int nmate;
0140 for (G4int ii = 0; ii < nMaterials; ii++) {
0141 fin >> nmate >> stemp;
0142 G4cout << "DicomPartialDetectorConstruction::ReadPhantomData reading nmate " << ii << " = "
0143 << nmate << " mate " << stemp << G4endl;
0144 if (ii != nmate)
0145 G4Exception("DicomPartialDetectorConstruction::ReadPhantomData", "", FatalErrorInArgument,
0146 "Material number should be in increasing order: \
0147 wrong material number ");
0148 }
0149
0150 fin >> fNoVoxelsX >> fNoVoxelsY >> fNoVoxelsZ;
0151 G4cout << "DicomPartialDetectorConstruction::ReadPhantomData nVoxel X/Y/Z " << fNoVoxelsX << " "
0152 << fNoVoxelsY << " " << fNoVoxelsZ << G4endl;
0153 fin >> fOffsetX >> fDimX;
0154 fDimX = (fDimX - fOffsetX) / fNoVoxelsX;
0155 fin >> fOffsetY >> fDimY;
0156 fDimY = (fDimY - fOffsetY) / fNoVoxelsY;
0157 fin >> fOffsetZ >> fDimZ;
0158 fDimZ = (fDimZ - fOffsetZ) / fNoVoxelsZ;
0159 G4cout << "DicomPartialDetectorConstruction::ReadPhantomData voxelDimX " << fDimX << " fOffsetX "
0160 << fOffsetX << G4endl;
0161 G4cout << "DicomPartialDetectorConstruction::ReadPhantomData voxelDimY " << fDimY << " fOffsetY "
0162 << fOffsetY << G4endl;
0163 G4cout << "DicomPartialDetectorConstruction::ReadPhantomData voxelDimZ " << fDimZ << " fOffsetZ "
0164 << fOffsetZ << G4endl;
0165
0166
0167 fNoVoxels = 0;
0168
0169
0170
0171 G4int ifxmin1, ifxmax1;
0172 for (G4int iz = 0; iz < fNoVoxelsZ; iz++) {
0173 std::map<G4int, G4int> ifmin, ifmax;
0174 for (G4int iy = 0; iy < fNoVoxelsY; iy++) {
0175 fin >> ifxmin1 >> ifxmax1;
0176
0177
0178 ifmin[iy] = ifxmin1;
0179 ifmax[iy] = ifxmax1;
0180 G4int ifxdiff = ifxmax1 - ifxmin1 + 1;
0181 if (ifxmax1 == -1 && ifxmin1 == -1) ifxdiff = 0;
0182 fFilledIDs.insert(std::pair<G4int, G4int>(ifxdiff + fNoVoxels - 1, ifxmin1));
0183 G4cout << "DicomPartialDetectorConstruction::ReadPhantomData insert "
0184 << " FilledIDs " << ifxdiff + fNoVoxels - 1 << " min " << ifxmin1
0185 << " N= " << fFilledIDs.size() << G4endl;
0186
0187 for (G4int ix = 0; ix < fNoVoxelsX; ix++) {
0188 if (ix >= G4int(ifxmin1) && ix <= G4int(ifxmax1)) {
0189 fNoVoxels++;
0190 }
0191 else {
0192 }
0193 }
0194 }
0195 fFilledMins[iz] = ifmin;
0196 fFilledMaxs[iz] = ifmax;
0197 }
0198
0199
0200 G4int mateID1;
0201 fMateIDs = new size_t[fNoVoxelsX * fNoVoxelsY * fNoVoxelsZ];
0202 G4int copyNo = 0;
0203 for (G4int iz = 0; iz < fNoVoxelsZ; iz++) {
0204 std::map<G4int, G4int> ifmin = fFilledMins[iz];
0205 std::map<G4int, G4int> ifmax = fFilledMaxs[iz];
0206 for (G4int iy = 0; iy < fNoVoxelsY; iy++) {
0207 ifxmin1 = ifmin[iy];
0208 ifxmax1 = ifmax[iy];
0209 for (G4int ix = 0; ix < fNoVoxelsX; ix++) {
0210 if (ix >= G4int(ifxmin1) && ix <= G4int(ifxmax1)) {
0211 fin >> mateID1;
0212 if (mateID1 < 0 || mateID1 >= nMaterials) {
0213 G4Exception("DicomPartialDetectorConstruction::ReadPhantomData", "", FatalException,
0214 G4String("Wrong index in phantom file: It should be between 0 and "
0215 + G4UIcommand::ConvertToString(nMaterials - 1) + ", while it is "
0216 + G4UIcommand::ConvertToString(mateID1))
0217 .c_str());
0218 }
0219 fMateIDs[copyNo] = mateID1;
0220 copyNo++;
0221 }
0222 }
0223 }
0224 }
0225
0226 ReadVoxelDensitiesPartial(fin);
0227
0228 fin.close();
0229 }
0230
0231
0232 void DicomPartialDetectorConstruction::ReadVoxelDensitiesPartial(std::ifstream& fin)
0233 {
0234 std::map<G4int, std::pair<G4double, G4double>> densiMinMax;
0235 std::map<G4int, std::pair<G4double, G4double>>::iterator mpite;
0236 for (G4int ii = 0; ii < G4int(fOriginalMaterials.size()); ++ii) {
0237 densiMinMax[ii] = std::pair<G4double, G4double>(DBL_MAX, -DBL_MAX);
0238 }
0239
0240
0241
0242 char* part = std::getenv("DICOM_CHANGE_MATERIAL_DENSITY");
0243 G4double densityDiff = -1.;
0244 if (part) densityDiff = G4UIcommand::ConvertToDouble(part);
0245 std::map<G4int, G4double> densityDiffs;
0246 if (densityDiff != -1.) {
0247 for (G4int ii = 0; ii < G4int(fOriginalMaterials.size()); ++ii) {
0248 densityDiffs[ii] = densityDiff;
0249
0250 }
0251 }
0252 else {
0253 if (fMaterials.size() == 0) {
0254 for (unsigned int ii = 0; ii < fOriginalMaterials.size(); ++ii) {
0255 fMaterials.push_back(fOriginalMaterials[ii]);
0256 }
0257 }
0258 }
0259
0260
0261
0262 std::map<std::pair<G4Material*, G4int>, matInfo*> newMateDens;
0263
0264 G4double dens1;
0265 G4int ifxmin1, ifxmax1;
0266
0267
0268 G4int copyNo = 0;
0269 for (G4int iz = 0; iz < fNoVoxelsZ; ++iz) {
0270 std::map<G4int, G4int> ifmin = fFilledMins[iz];
0271 std::map<G4int, G4int> ifmax = fFilledMaxs[iz];
0272 for (G4int iy = 0; iy < fNoVoxelsY; ++iy) {
0273 ifxmin1 = ifmin[iy];
0274 ifxmax1 = ifmax[iy];
0275 for (G4int ix = 0; ix < fNoVoxelsX; ++ix) {
0276 if (ix >= G4int(ifxmin1) && ix <= G4int(ifxmax1)) {
0277 fin >> dens1;
0278
0279
0280 mpite = densiMinMax.find(G4int(fMateIDs[copyNo]));
0281 if (dens1 < (*mpite).second.first) (*mpite).second.first = dens1;
0282 if (dens1 > (*mpite).second.second) (*mpite).second.second = dens1;
0283
0284
0285 G4int mateID = G4int(fMateIDs[copyNo]);
0286 G4Material* mate = fOriginalMaterials[mateID];
0287
0288
0289 if (std::fabs(dens1 - mate->GetDensity() / g * cm3) < 1.e-9) continue;
0290
0291
0292
0293
0294 G4String newMateName = mate->GetName();
0295
0296 G4int densityBin = 0;
0297
0298
0299
0300 if (densityDiff != -1.) {
0301 densityBin = (G4int(dens1 / densityDiffs[mateID]));
0302 newMateName = mate->GetName() + G4UIcommand::ConvertToString(densityBin);
0303 }
0304
0305
0306 std::pair<G4Material*, G4int> matdens(mate, densityBin);
0307
0308 auto mppite = newMateDens.find(matdens);
0309 if (mppite != newMateDens.cend()) {
0310 matInfo* mi = (*mppite).second;
0311 mi->fSumdens += dens1;
0312 mi->fNvoxels++;
0313 fMateIDs[copyNo] = fOriginalMaterials.size() - 1 + mi->fId;
0314
0315
0316 }
0317 else {
0318 matInfo* mi = new matInfo;
0319 mi->fSumdens = dens1;
0320 mi->fNvoxels = 1;
0321 mi->fId = G4int(newMateDens.size() + 1);
0322 newMateDens[matdens] = mi;
0323 fMateIDs[copyNo] = fOriginalMaterials.size() - 1 + mi->fId;
0324
0325
0326 }
0327 copyNo++;
0328
0329
0330
0331 }
0332 }
0333 }
0334 }
0335
0336
0337
0338 for (auto mimite = fOriginalMaterials.cbegin(); mimite != fOriginalMaterials.cend(); ++mimite) {
0339 fPhantomMaterials.push_back((*mimite));
0340 }
0341
0342
0343 for (auto mppite = newMateDens.cbegin(); mppite != newMateDens.cend(); ++mppite) {
0344 G4double averdens = (*mppite).second->fSumdens / (*mppite).second->fNvoxels;
0345 G4double saverdens = G4int(1000.001 * averdens) / 1000.;
0346 G4cout << "GmReadPhantomGeometry::ReadVoxelDensities AVER DENS " << averdens << " -> "
0347 << saverdens << " -> " << G4int(1000 * averdens) << " " << G4int(1000 * averdens) / 1000
0348 << " " << G4int(1000 * averdens) / 1000. << G4endl;
0349
0350 G4cout << "GmReadPhantomGeometry::ReadVoxelDensities AVER DENS " << averdens << " -> "
0351 << saverdens << " -> " << G4UIcommand::ConvertToString(saverdens) << " Nvoxels "
0352 << (*mppite).second->fNvoxels << G4endl;
0353 G4String mateName =
0354 ((*mppite).first).first->GetName() + "_" + G4UIcommand::ConvertToString(saverdens);
0355 fPhantomMaterials.push_back(
0356 BuildMaterialWithChangingDensity((*mppite).first.first, G4float(averdens), mateName));
0357 }
0358 }
0359
0360
0361 void DicomPartialDetectorConstruction::ConstructPhantomContainer()
0362 {
0363
0364
0365
0366
0367 G4String contname = "PhantomContainer";
0368
0369
0370 G4Tubs* container_tube = new G4Tubs(contname, 0., 200., 100., 0., 360 * deg);
0371
0372 fContainer_logic = new G4LogicalVolume(container_tube, fAir, contname, 0, 0, 0);
0373
0374 G4ThreeVector posCentreVoxels(0., 0., 0.);
0375
0376 G4RotationMatrix* rotm = new G4RotationMatrix;
0377
0378 fContainer_phys = new G4PVPlacement(rotm,
0379 posCentreVoxels,
0380 fContainer_logic,
0381 contname,
0382 fWorld_logic,
0383 false,
0384 1);
0385 }
0386
0387
0388 void DicomPartialDetectorConstruction::ConstructPhantom()
0389 {
0390 G4String OptimAxis = "kXAxis";
0391 G4bool bSkipEqualMaterials = 0;
0392 G4int regStructureID = 2;
0393
0394 G4ThreeVector posCentreVoxels(0., 0., 0.);
0395
0396
0397 G4String voxelName = "phantom";
0398 G4Box* phantom_solid = new G4Box(voxelName, fDimX / 2., fDimY / 2., fDimZ / 2.);
0399 G4LogicalVolume* phantom_logic = new G4LogicalVolume(phantom_solid, fAir, voxelName, 0, 0, 0);
0400 G4bool pVis = 0;
0401 if (!pVis) {
0402 G4VisAttributes* visAtt = new G4VisAttributes(FALSE);
0403 phantom_logic->SetVisAttributes(visAtt);
0404 }
0405
0406 G4double theSmartless = 0.5;
0407
0408 phantom_logic->SetSmartless(theSmartless);
0409
0410 fPartialPhantomParam = new G4PartialPhantomParameterisation();
0411
0412 fPartialPhantomParam->SetMaterials(fPhantomMaterials);
0413 fPartialPhantomParam->SetVoxelDimensions(fDimX / 2., fDimY / 2., fDimZ / 2.);
0414 fPartialPhantomParam->SetNoVoxels(fNoVoxelsX, fNoVoxelsY, fNoVoxelsZ);
0415 fPartialPhantomParam->SetMaterialIndices(fMateIDs);
0416
0417 fPartialPhantomParam->SetFilledIDs(fFilledIDs);
0418
0419 fPartialPhantomParam->SetFilledMins(fFilledMins);
0420
0421 fPartialPhantomParam->BuildContainerWalls();
0422
0423
0424
0425
0426 G4PVParameterised* phantom_phys = 0;
0427 if (OptimAxis == "kUndefined") {
0428 phantom_phys = new G4PVParameterised(voxelName, phantom_logic, fContainer_logic, kUndefined,
0429 fNoVoxels, fPartialPhantomParam);
0430 }
0431 else if (OptimAxis == "kXAxis") {
0432
0433 phantom_phys = new G4PVParameterised(voxelName, phantom_logic, fContainer_logic, kXAxis,
0434 fNoVoxels, fPartialPhantomParam);
0435 fPartialPhantomParam->SetSkipEqualMaterials(bSkipEqualMaterials);
0436 }
0437 else {
0438 G4Exception("GmReadPhantomGeometry::ConstructPhantom", "", FatalErrorInArgument,
0439 G4String("Wrong argument to parameter \
0440 GmReadPhantomGeometry:Phantom:OptimAxis: \
0441 Only allowed 'kUndefined' or 'kXAxis', it is: "
0442 + OptimAxis)
0443 .c_str());
0444 }
0445
0446 phantom_phys->SetRegularStructureId(regStructureID);
0447 }