Newer
Older
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
/// \file /src/DetectorConstruction.cc
/// \brief Implementation of the DetectorConstruction class
//
//
// USER //
#include "DetectorConstruction.hh"
#include "DetectorMessenger.hh"
#include "Materials.hh"
#include "PMTSD.hh"
#include "CADMesh.hh"
#include <math.h>
// GEANT4 //
#include "G4Element.hh"
#include "G4SDManager.hh"
#include "G4RunManager.hh"
#include "G4GeometryManager.hh"
#include "G4PhysicalVolumeStore.hh"
#include "G4LogicalVolumeStore.hh"
#include "G4SolidStore.hh"
#include "G4LogicalBorderSurface.hh"
#include "G4LogicalSkinSurface.hh"
#include "G4OpticalSurface.hh"
#include "G4ThreeVector.hh"
#include "G4PVPlacement.hh"
#include "G4SystemOfUnits.hh"
#include "G4Tubs.hh"
#include "G4Trd.hh"
#include "G4SubtractionSolid.hh"
#include "G4NistManager.hh"
#include "G4VisAttributes.hh"
#include "G4VisExtent.hh"
#include "G4Colour.hh"
#include "G4UImanager.hh"
/*
*
*/
DetectorConstruction::DetectorConstruction()
: G4VUserDetectorConstruction(),
m_worldDim( new G4ThreeVector(1.0*m, 1.0*m, 1.0*m) ),
m_LGpos( new G4ThreeVector() ),
m_pmtPos( new G4ThreeVector(28.5*mm, 35.0*mm, -7.5*mm) ),
m_rotation( new G4RotationMatrix() ),
m_pmtDia(10.5*mm),
Chad Lantz
committed
m_PMTthickness(0.001*mm),
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
m_ConstructionHasBeenDone(false),
m_UsingCADmodel(true),
m_logicWorld(0),
m_physLG(0),
m_physPMT(0),
m_DetectorMessenger(nullptr)
{
materials = Materials::getInstance();
materials->UseOpticalMaterials(true);
materials->DefineOpticalProperties();
m_DetectorMessenger = new DetectorMessenger(this);
m_runMan = G4RunManager::GetRunManager();
}
/*
*
*/
DetectorConstruction::~DetectorConstruction(){
delete m_DetectorMessenger;
}
/*
* Execute geometry.mac here and construct the world according
* to what it contains
*/
G4VPhysicalVolume* DetectorConstruction::Construct(){
if ( m_ConstructionHasBeenDone ) {
G4GeometryManager::GetInstance()->OpenGeometry();
G4PhysicalVolumeStore::GetInstance()->Clean();
G4LogicalVolumeStore::GetInstance()->Clean();
G4SolidStore::GetInstance()->Clean();
G4LogicalSkinSurface::CleanSurfaceTable();
G4LogicalBorderSurface::CleanSurfaceTable();
} else {
G4UImanager* UImanager = G4UImanager::GetUIpointer();
UImanager->ApplyCommand("/control/execute geometry.mac");
BuildPMT();
}
if(!m_logicWorld) BuildWorld();
if(!m_physLG) BuildDefaultLG();
PlaceGeometry();
m_ConstructionHasBeenDone = true;
return m_physWorld;
}
/*
*
*/
void DetectorConstruction::BuildWorld(){
bool checkOverlaps = false;
//----------------- Define the world volume -----------------//
m_solidWorld =
new G4Box("World", //name
m_worldDim->x(), //sizeX
m_worldDim->y(), //sizeY
m_worldDim->z()); //sizeZ
m_logicWorld =
new G4LogicalVolume(m_solidWorld, //solid
materials->Air, //material
"World"); //name
m_physWorld =
new G4PVPlacement(0, //no rotation
G4ThreeVector(), //at (0,0,0)
m_logicWorld, //logical volume
"World", //name
0, //mother volume
false, //no boolean operation
0, //copy number
checkOverlaps); //overlaps checking
// G4VisAttributes* boxVisAtt_world= new G4VisAttributes(); ***UNCOMMENT FOR VISIBLE WORLD VOLUME***
G4VisAttributes* boxVisAtt_world= new G4VisAttributes(G4VisAttributes::Invisible);
m_logicWorld ->SetVisAttributes(boxVisAtt_world);
}
/*
* Make the default light guide
*/
void DetectorConstruction::BuildDefaultLG( ){
// Build the light guide here up until the logical volume
// Maybe build the aluminum portion into a single CAD solid and add
// fibers and air here
UseCADModel("../models/LED-GMS-light-guide.stl");
bool CHECK_OVERLAPS = true;
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
//Change these variables to what they really should be
double fiberLength = 270*mm;
double core_diam = 0.600*mm;
double cladding_diam = 0.660*mm;
double buffer_diam = 0.710*mm;
//Core
m_fiberCore = new G4Tubs("fiber_core", // name
0.0*mm, // inner radius
core_diam/2.0,// outter radius
fiberLength, // length
0.0*deg, // sweep starting angle
360.0*deg); // sweep stopping angle
m_logicCore = new G4LogicalVolume( m_fiberCore, // solid to be created from
materials->pQuartz, // material
"fiber_logicCore"); // name
//Cladding
m_fiberCladding = new G4Tubs("fiber_cladding", // name
core_diam/2.0, // inner radius
cladding_diam/2.0, // outter radius
fiberLength, // length
0.0*deg, // sweep starting angle
360.0*deg); // sweep stopping angle
m_logicCladding = new G4LogicalVolume( m_fiberCladding, // solid to be created from
materials->pQuartz, // material
"fiber_logicCladding"); // name
//Buffer
m_fiberBuffer = new G4Tubs("fiber_buffer", // name
cladding_diam/2.0,// inner radius
buffer_diam/2.0, // outter radius
fiberLength, // length
0.0*deg, // sweep starting angle
360.0*deg); // sweep stopping angle
m_logicBuffer = new G4LogicalVolume( m_fiberBuffer, // solid to be created from
materials->pQuartz, // material
"fiber_logicBuffer"); // name
// Place the fibers
G4RotationMatrix* fiberRotation = new G4RotationMatrix();
fiberRotation->rotateX(90.*deg);
char name[32];
for(int i = 0; i < 32; i++){
// calculate cooridnates for center of each fiber (use CAD model for placement):
double x = 8.5 + 1.20*i; // x-offset + fiber spacing
double y = 345;
double z = -6.00;
//Core
sprintf(name,"fiberCore_%d", i);
m_physCore.push_back(
new G4PVPlacement(fiberRotation, //Rotation
G4ThreeVector( x , y , z ), //Position
m_logicCore, //Logical volume this is built from
name, //Name
m_logicWorld, //Mother volume
false, //If there are boolean operations
i, //Copy number
CHECK_OVERLAPS) ); //Check for overlaps with other geometry
//Cladding
sprintf(name,"fiberCladding_%d", i);
m_physCladding.push_back(
new G4PVPlacement(fiberRotation, //Rotation
G4ThreeVector( x , y , z ), //Position
m_logicCladding, //Logical volume this is built from
name, //Name
m_logicWorld, //Mother volume
false, //If there are boolean operations
i, //Copy number
CHECK_OVERLAPS) ); //Check for overlaps with other geometry
//Core
sprintf(name,"fiberBuffer_%d", i);
m_physBuffer.push_back(
new G4PVPlacement(fiberRotation, //Rotation
G4ThreeVector( x , y, z ), //Position
m_logicBuffer, //Logical volume this is built from
name, //Name
m_logicWorld, //Mother volume
false, //If there are boolean operations
i, //Copy number
CHECK_OVERLAPS) ); //Check for overlaps with other geometry
}
}
/*
* Make the PMT logical volume and Sensitvie Detector
*/
void DetectorConstruction::BuildPMT(){
Chad Lantz
committed
G4SDManager* SDman = G4SDManager::GetSDMpointer();
m_SDnames.push_back("MyPMT");
PMTSD* PMT = new PMTSD(m_SDnames.back(), false); // isIntermediate set to false. This is the final detector
SDman->AddNewDetector( PMT );
m_solidPMT =
new G4Tubs("PMT", //name
0.0*mm, //Inner radius
m_pmtDia/2.0, //Outter radius
m_PMTthickness, //Height
0.0*deg, //Rotation start
360.0*deg); //Sweep
m_logicPMT =
new G4LogicalVolume(m_solidPMT, //solid
materials->Air, //material
"PMT"); //name
G4VisAttributes* VisAtt_PMT = new G4VisAttributes(G4Colour(1.0,1.0,0.6,0.7));
m_logicPMT->SetVisAttributes(VisAtt_PMT);
m_logicPMT->SetSensitiveDetector( PMT );
/***********************************
* Intermediate Sensitive Detector 1
**********************************/
m_SDnames.push_back("IntSD1");
PMT = new PMTSD(m_SDnames.back(), true); // isIntermediate set to true
SDman->AddNewDetector( PMT );
Chad Lantz
committed
m_solidIntSD.push_back( new G4Box("soldIntSD1",20.00*mm, 0.001*mm, 2.00*mm) );
m_logicIntSD.push_back( new G4LogicalVolume(m_solidIntSD.back(), materials->Air, "logicIntSD1") );
m_logicIntSD.back()->SetVisAttributes(VisAtt_PMT);
m_logicIntSD.back()->SetSensitiveDetector( PMT );
/***********************************
* Intermediate Sensitive Detector 2
**********************************/
m_SDnames.push_back("IntSD2");
PMT = new PMTSD(m_SDnames.back(), true); // isIntermediate set to true
SDman->AddNewDetector( PMT );
m_solidIntSD.push_back( new G4Box("soldIntSD2",50.00*mm, 0.001*mm, 2.00*mm) );
m_logicIntSD.push_back( new G4LogicalVolume(m_solidIntSD.back(), materials->Air, "logicIntSD2") );
m_logicIntSD.back()->SetVisAttributes(VisAtt_PMT);
m_logicIntSD.back()->SetSensitiveDetector( PMT );
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
}
/*
* Place the geometry. This is done in it's own step in case
* the user has specified a CAD model to be used
*/
void DetectorConstruction::PlaceGeometry(){
//----------------- Place the LightGuide -----------------//
m_physLG = new G4PVPlacement(m_rotation,
*m_LGpos,
m_logicLG,
"LightGuide",
m_logicWorld,
false,
0);
//----------------- Place the PMT -----------------//
m_physPMT = new G4PVPlacement(new G4RotationMatrix(),
*m_pmtPos,
m_logicPMT,
"PMT",
m_logicWorld,
false,
Daniel R. MacLean
committed
0,
CHECK_OVERLAPS) );
//----------------- Place Intermediate Detector 1 -----------------//
m_physIntSD.push_back(
new G4PVPlacement(new G4RotationMatrix(),
G4ThreeVector( 28.50*mm, 615.00*mm, -5.50*mm),
m_logicIntSD[0],
"IntSD1",
m_logicWorld,
false,
Daniel R. MacLean
committed
0,
CHECK_OVERLAPS) );
//----------------- Place Intermediate Detector 2 -----------------//
m_physIntSD.push_back(
new G4PVPlacement(new G4RotationMatrix(),
G4ThreeVector( 28.50*mm, 57.50*mm, -6.00*mm),
m_logicIntSD[0],
"IntSD2",
m_logicWorld,
false,
Daniel R. MacLean
committed
0,
CHECK_OVERLAPS) );
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
//----------------- Define Optical Borders -----------------//
// One of these is correct. The order of the logical volumes is different
// between the two. This is specific to the direction of light i.e. from
// volume a to volume b or vice versa
// m_Surface = new G4LogicalBorderSurface("AlSurface",
// m_physLightGuide,
// m_physWorld,
// materials->AlSurface ) );
//
m_Surface = new G4LogicalBorderSurface("AlSurface",
m_physWorld,
m_physLG,
materials->AlSurface );
}
/*
* Set the dimensions of the world volume.
* If the volume exists modify it, otherwise build it.
*/
void DetectorConstruction::SetWorldVolume(G4ThreeVector arg){
if(m_ConstructionHasBeenDone){
m_solidWorld->SetXHalfLength( arg.x() );
m_solidWorld->SetYHalfLength( arg.y() );
m_solidWorld->SetZHalfLength( arg.z() );
m_runMan->GeometryHasBeenModified();
G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/rebuild");
} else {
delete m_worldDim;
m_worldDim = new G4ThreeVector(arg);
BuildWorld();
}
}
/*
* If the world already exists, rotate the light guide
* otherwise set the rotation for the light guide that will be built
*/
void DetectorConstruction::SetRotation(G4ThreeVector arg){
if(m_rotation) delete m_rotation;
m_rotation = new G4RotationMatrix();
m_rotation->rotateX(arg.x());
m_rotation->rotateY(arg.y());
m_rotation->rotateZ(arg.z());
if(m_ConstructionHasBeenDone){
m_physLG->SetRotation(m_rotation);
m_runMan->GeometryHasBeenModified();
G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/rebuild");
}
}
/*
* If the world already exists, move the light guide. If there is more
* than one light guide, set the position and rebuild.
* otherwise set the location for the light guide that will be built
*/
void DetectorConstruction::SetTranslation(G4ThreeVector arg){
if(m_ConstructionHasBeenDone){
m_physLG->SetTranslation(arg);
m_runMan->GeometryHasBeenModified();
G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/rebuild");
} else {
m_LGpos = new G4ThreeVector(arg);
}
}
/*
* If the world already exists, move the PMT. If there is more
* than one PMT, set the position and rebuild.
* otherwise set the location for the PMT that will be built
*/
void DetectorConstruction::SetPMTTranslation(G4ThreeVector arg){
if(m_ConstructionHasBeenDone){
m_physPMT->SetTranslation(arg);
m_runMan->GeometryHasBeenModified();
G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/rebuild");
} else {
m_pmtPos = new G4ThreeVector(arg);
}
}
/*
* If the world already exists, modify the PMT
* otherwise set the diameter for PMT that will be built
*/
void DetectorConstruction::SetPMTDiameter(G4double arg){
if(m_ConstructionHasBeenDone){
m_solidPMT->SetOuterRadius(arg/2.0);
m_runMan->GeometryHasBeenModified();
G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/rebuild");
} else {
m_pmtDia = arg;
}
}
/*
* Builds a light guide logical volume from CAD model file
*/
void DetectorConstruction::UseCADModel(G4String fileName){
//Delete anything we are going to redefine
if(m_ConstructionHasBeenDone){
delete m_logicLG;
delete m_physLG;
delete m_physPMT;
delete m_Surface;
}
float xSize=0.0, ySize=0.0, zSize=0.0;
G4String fileType = fileName.substr( fileName.last('.') + 1, fileName.size() - fileName.last('.'));
if(fileType == "stl"){
auto mesh = CADMesh::TessellatedMesh::FromSTL((char*) fileName.c_str());
// auto mesh = CADMesh::TessellatedMesh::From((char*) fileName.c_str());
mesh->SetScale(mm);
mesh->SetOffset( G4ThreeVector(0, 0, 0) );
mesh->SetReverse(false);
m_logicLG =
new G4LogicalVolume(mesh->GetSolid(), //solid
materials->Al, //material
"LightGuide"); //name
}else{
G4cout << "File type not supported" << G4endl;
}
if(m_logicLG !=0 ){
//Print the extent to the console to help the user position the light guide
char message[64];
G4VisExtent extent = m_logicLG->GetSolid()->GetExtent();
xSize = extent.GetXmax() - extent.GetXmin();
ySize = extent.GetYmax() - extent.GetYmin();
zSize = extent.GetZmax() - extent.GetZmin();
G4cout << "===== Light guide extent =====" << G4endl;
sprintf(message,"Xmin = %04.2f, Xmax = %04.2f: Width = %04.2f", extent.GetXmin(), extent.GetXmax(), xSize );
G4cout << message << G4endl;
sprintf(message,"Ymin = %04.2f, Ymax = %04.2f: Height = %04.2f", extent.GetYmin(), extent.GetYmax(), ySize );
G4cout << message << G4endl;
sprintf(message,"Zmin = %04.2f, Zmax = %04.2f: Depth = %04.2f", extent.GetZmin(), extent.GetZmax(), zSize );
G4cout << message << G4endl;
}
if(m_pmtPos == 0) m_pmtPos = new G4ThreeVector( );
if(m_ConstructionHasBeenDone){
PlaceGeometry();
m_runMan->GeometryHasBeenModified();
G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/rebuild");
}
G4cout << "Using " << fileName << " for CAD model" << G4endl;
}
/*
* Set the surface model for the light guide
*/
void DetectorConstruction::SetSurfaceModel(const G4OpticalSurfaceModel model){
materials->AlSurface->SetModel(model);
if(m_ConstructionHasBeenDone){
m_runMan->GeometryHasBeenModified();
}
}
/*
*
*/
void DetectorConstruction::SetSurfaceFinish(const G4OpticalSurfaceFinish finish){
materials->AlSurface->SetFinish(finish);
if(m_ConstructionHasBeenDone){
m_runMan->GeometryHasBeenModified();
}
}
/*
*
*/
void DetectorConstruction::SetSurfaceType(const G4SurfaceType type){
materials->AlSurface->SetType(type);
if(m_ConstructionHasBeenDone){
m_runMan->GeometryHasBeenModified();
}
}
/*
*
*/
void DetectorConstruction::SetSurfaceSigmaAlpha(G4double v){
materials->AlSurface->SetSigmaAlpha(v);
if(m_ConstructionHasBeenDone){
G4RunManager::GetRunManager()->GeometryHasBeenModified();
}
G4cout << "Surface sigma alpha set to: " << materials->AlSurface->GetSigmaAlpha() << G4endl;
}
/*
* Set the material property table of the surface
* of the light guide
*/
void DetectorConstruction::AddSurfaceMPV(const char* c, G4MaterialPropertyVector* mpv){
mpv->SetSpline(true);
materials->GetMPTArray().at(1)->AddProperty(c, mpv);
materials->AlSurface->SetMaterialPropertiesTable(materials->GetMPTArray().at(1));
G4cout << "The MPT for the surface is now: " << G4endl;
materials->GetMPTArray().at(1)->DumpTable();
G4cout << "............." << G4endl;
}