File indexing completed on 2025-08-05 08:17:40
0001 #include "BeamLineMagnetDetector.h"
0002 #include "BeamLineMagnetDisplayAction.h"
0003
0004 #include <phparameter/PHParameters.h>
0005
0006 #include <g4main/PHG4Detector.h> // for PHG4Detector
0007 #include <g4main/PHG4DisplayAction.h> // for PHG4DisplayAction
0008 #include <g4main/PHG4Subsystem.h>
0009
0010 #include <phool/phool.h>
0011
0012 #include <TSystem.h>
0013
0014 #include <Geant4/G4ChordFinder.hh>
0015 #include <Geant4/G4ClassicalRK4.hh>
0016 #include <Geant4/G4FieldManager.hh>
0017 #include <Geant4/G4LogicalVolume.hh>
0018 #include <Geant4/G4Mag_UsualEqRhs.hh>
0019 #include <Geant4/G4MagneticField.hh>
0020 #include <Geant4/G4PVPlacement.hh>
0021 #include <Geant4/G4PhysicalConstants.hh>
0022 #include <Geant4/G4QuadrupoleMagField.hh>
0023 #include <Geant4/G4RotationMatrix.hh>
0024 #include <Geant4/G4SystemOfUnits.hh>
0025 #include <Geant4/G4ThreeVector.hh> // for G4ThreeVector
0026 #include <Geant4/G4Transform3D.hh> // for G4Transform3D
0027 #include <Geant4/G4Tubs.hh>
0028 #include <Geant4/G4Types.hh> // for G4double, G4bool
0029 #include <Geant4/G4UniformMagField.hh>
0030
0031 #include <CLHEP/Units/SystemOfUnits.h> // for cm, deg, tesla, twopi, meter
0032
0033 #include <cassert>
0034 #include <cstdlib> // for exit
0035 #include <iostream> // for operator<<, basic_ostream
0036
0037 class G4VSolid;
0038 class PHCompositeNode;
0039
0040
0041 BeamLineMagnetDetector::BeamLineMagnetDetector(PHG4Subsystem *subsys, PHCompositeNode *Node, PHParameters *parameters, const std::string &dnam, const int magnet_id)
0042 : PHG4Detector(subsys, Node, dnam)
0043 , m_Params(parameters)
0044 , m_DisplayAction(dynamic_cast<BeamLineMagnetDisplayAction *>(subsys->GetDisplayAction()))
0045 , m_MagnetId(magnet_id)
0046 {
0047 }
0048
0049
0050 int BeamLineMagnetDetector::IsInBeamLineMagnet(const G4VPhysicalVolume *volume) const
0051 {
0052 if (volume == magnet_physi)
0053 {
0054 return 1;
0055 }
0056 if (volume == magnet_core_physi)
0057 {
0058 return -2;
0059 }
0060 if (volume == magnet_iron_physi)
0061 {
0062 return -1;
0063 }
0064 return 0;
0065 }
0066
0067
0068 void BeamLineMagnetDetector::ConstructMe(G4LogicalVolume *logicMother)
0069 {
0070
0071 G4ThreeVector origin(m_Params->get_double_param("place_x") * cm,
0072 m_Params->get_double_param("place_y") * cm,
0073 m_Params->get_double_param("place_z") * cm);
0074
0075
0076 G4RotationMatrix *rotm = new G4RotationMatrix();
0077 rotm->rotateX(m_Params->get_double_param("rot_x") * deg);
0078 rotm->rotateY(m_Params->get_double_param("rot_y") * deg);
0079 rotm->rotateZ(m_Params->get_double_param("rot_z") * deg);
0080
0081
0082 G4VSolid *magnet_mother_solid = new G4Tubs(GetName().append("_Mother"),
0083 0,
0084 m_Params->get_double_param("outer_radius") * cm,
0085 m_Params->get_double_param("length") * cm / 2., 0, twopi);
0086 G4LogicalVolume *magnet_mother_logic = new G4LogicalVolume(magnet_mother_solid,
0087 GetDetectorMaterial("G4_Galactic"),
0088 GetName(),
0089 nullptr, nullptr, nullptr);
0090
0091 m_DisplayAction->AddVolume(magnet_mother_logic, "OFF");
0092 new G4PVPlacement(G4Transform3D(*rotm, origin),
0093 magnet_mother_logic,
0094 GetName().append("_Mother"),
0095 logicMother, false, m_MagnetId, OverlapCheck());
0096
0097 G4ThreeVector field_origin(origin);
0098 G4RotationMatrix *field_rotm = rotm;
0099
0100
0101 if (GetMySubsystem()->GetMotherSubsystem())
0102 {
0103 if (Verbosity() > 0)
0104 {
0105 std::cout << __PRETTY_FUNCTION__ << ": set field using the global coordinate system, as the magnet is a daughter vol. of "
0106 << GetMySubsystem()->GetMotherSubsystem()->Name() << std::endl;
0107 }
0108
0109
0110 field_origin = G4ThreeVector(m_Params->get_double_param("field_global_position_x") * cm,
0111 m_Params->get_double_param("field_global_position_y") * cm,
0112 m_Params->get_double_param("field_global_position_z") * cm);
0113
0114
0115
0116 field_rotm = new G4RotationMatrix();
0117 rotm->rotateX(m_Params->get_double_param("field_global_rot_x") * deg);
0118 rotm->rotateY(m_Params->get_double_param("field_global_rot_y") * deg);
0119 rotm->rotateZ(m_Params->get_double_param("field_global_rot_z") * deg);
0120 }
0121
0122 std::string magnettype = m_Params->get_string_param("magtype");
0123 if (magnettype == "DIPOLE")
0124 {
0125 G4ThreeVector field(m_Params->get_double_param("field_x") * tesla,
0126 m_Params->get_double_param("field_y") * tesla,
0127 m_Params->get_double_param("field_z") * tesla);
0128
0129
0130
0131 field.transform(*field_rotm);
0132 m_magField = new G4UniformMagField(field);
0133 if (Verbosity() > 0)
0134 {
0135 std::cout << "Creating DIPOLE with field x: " << field.x() / tesla
0136 << ", y: " << field.y() / tesla
0137 << ", z: " << field.z() / tesla
0138 << " and name " << GetName() << std::endl;
0139 }
0140 }
0141 else if (magnettype == "QUADRUPOLE")
0142 {
0143 G4double fieldGradient = m_Params->get_double_param("fieldgradient") * tesla / meter;
0144
0145
0146
0147
0148 m_magField = new G4QuadrupoleMagField(fieldGradient, field_origin, field_rotm);
0149
0150 if (Verbosity() > 0)
0151 {
0152 std::cout << "Creating QUADRUPOLE with gradient " << fieldGradient << " and name " << GetName() << std::endl;
0153 std::cout << "at x, y, z = " << field_origin.x() << " , " << field_origin.y() << " , " << field_origin.z() << std::endl;
0154 std::cout << "with rotation around x, y, z axis by: " << field_rotm->phiX() << ", " << field_rotm->phiY() << ", " << field_rotm->phiZ() << std::endl;
0155 }
0156 }
0157 else
0158 {
0159 std::cout << __PRETTY_FUNCTION__ << " : Fatal error, magnet type of " << magnettype << " is not yet supported" << std::endl;
0160 exit(1);
0161 }
0162
0163 if (!m_magField && Verbosity() > 0)
0164 {
0165 std::cout << PHWHERE << " No magnetic field specified for " << GetName()
0166 << " of type " << magnettype << std::endl;
0167 }
0168
0169
0170 G4VSolid *magnet_iron_solid = new G4Tubs(GetName().append("_Solid"),
0171 m_Params->get_double_param("inner_radius") * cm,
0172 m_Params->get_double_param("outer_radius") * cm,
0173 m_Params->get_double_param("length") * cm / 2., 0, twopi);
0174 G4LogicalVolume *magnet_iron_logic = new G4LogicalVolume(magnet_iron_solid,
0175 GetDetectorMaterial("G4_Fe"),
0176 GetName(),
0177 nullptr, nullptr, nullptr);
0178 m_DisplayAction->AddVolume(magnet_iron_logic, magnettype);
0179
0180 if (m_Params->get_double_param("skin_thickness") > 0)
0181 {
0182 if (m_Params->get_double_param("inner_radius") * cm + m_Params->get_double_param("skin_thickness") * cm >
0183 m_Params->get_double_param("outer_radius") * cm - m_Params->get_double_param("skin_thickness") * cm)
0184 {
0185 std::cout << "Magnet skin thickness " << m_Params->get_double_param("skin_thickness") << " too large, exceeds 2xmagnet thickness "
0186 << m_Params->get_double_param("outer_radius") * cm - m_Params->get_double_param("inner_radius") * cm
0187 << std::endl;
0188 gSystem->Exit(1);
0189 }
0190
0191 G4VSolid *magnet_core_solid = new G4Tubs(GetName().append("_Core"),
0192 m_Params->get_double_param("inner_radius") * cm + m_Params->get_double_param("skin_thickness") * cm,
0193 m_Params->get_double_param("outer_radius") * cm - m_Params->get_double_param("skin_thickness") * cm,
0194 (m_Params->get_double_param("length") * cm - m_Params->get_double_param("skin_thickness") * cm) / 2., 0, twopi);
0195 G4LogicalVolume *magnet_core_logic = new G4LogicalVolume(magnet_core_solid,
0196 GetDetectorMaterial("G4_Fe"),
0197 GetName(),
0198 nullptr, nullptr, nullptr);
0199 m_DisplayAction->AddVolume(magnet_core_logic, magnettype);
0200
0201 magnet_core_physi = new G4PVPlacement(nullptr, G4ThreeVector(0, 0, 0),
0202 magnet_core_logic,
0203 GetName().append("_Solid"),
0204 magnet_iron_logic, false, m_MagnetId, OverlapCheck());
0205 }
0206 magnet_iron_physi = new G4PVPlacement(nullptr, G4ThreeVector(0, 0, 0),
0207 magnet_iron_logic,
0208 GetName().append("_Solid"),
0209 magnet_mother_logic, false, m_MagnetId, OverlapCheck());
0210
0211 G4VSolid *magnet_field_solid = new G4Tubs(GetName().append("_Field_Solid"),
0212 0,
0213 m_Params->get_double_param("inner_radius") * cm,
0214 m_Params->get_double_param("length") * cm / 2., 0, twopi);
0215
0216 m_magnetFieldLogic = new G4LogicalVolume(magnet_field_solid,
0217 GetDetectorMaterial("G4_Galactic"),
0218 GetName(),
0219 nullptr, nullptr, nullptr);
0220
0221
0222 PHG4Subsystem *mysys = GetMySubsystem();
0223 mysys->SetLogicalVolume(m_magnetFieldLogic);
0224
0225 m_DisplayAction->AddVolume(m_magnetFieldLogic, "FIELDVOLUME");
0226
0227
0228
0229 magnet_physi = new G4PVPlacement(nullptr, G4ThreeVector(0, 0, 0),
0230 m_magnetFieldLogic,
0231 GetName(),
0232 magnet_mother_logic, false, m_MagnetId, OverlapCheck());
0233 }
0234
0235
0236 void BeamLineMagnetDetector::PostConstruction()
0237 {
0238
0239
0240
0241 assert(m_magField);
0242 assert(m_magnetFieldLogic);
0243
0244 if (Verbosity() > 0)
0245 {
0246 std::cout << __PRETTY_FUNCTION__ << ": set field to vol " << m_magnetFieldLogic->GetName() << " that include "
0247 << m_magnetFieldLogic->GetNoDaughters() << " daughter vols." << std::endl;
0248 }
0249
0250
0251 G4Mag_UsualEqRhs *localEquation = new G4Mag_UsualEqRhs(m_magField);
0252 G4ClassicalRK4 *localStepper = new G4ClassicalRK4(localEquation);
0253 G4double minStep = 0.25 * mm;
0254 G4ChordFinder *localChordFinder = new G4ChordFinder(m_magField, minStep, localStepper);
0255
0256 G4FieldManager *fieldMgr = new G4FieldManager();
0257 fieldMgr->SetDetectorField(m_magField);
0258 fieldMgr->SetChordFinder(localChordFinder);
0259 m_magnetFieldLogic->SetFieldManager(fieldMgr, true);
0260 }