#include #include #include #include #include #include #include #include #include #include #include using std::map; using std::string; using std::vector; using std::pair; using CLHEP::deg; using CLHEP::mm; namespace RAT { map GeoFactory::fsFactories; GeoFactory::GeoFactory( const std::string& name ) { fsFactories[name] = this; } void GeoFactory::ConstructVolume( const std::string& factory, DBLinkPtr table, const bool checkOverlaps ) { if( fsFactories.count( factory ) == 0 ) Log::Die( "GeoFactory::ConstructVolume: No " + factory + " factory." ); else fsFactories[factory]->Construct( table, checkOverlaps ); } void GeoFactory::Destruct() { for( map::iterator iTer = fsFactories.begin(); iTer != fsFactories.end(); ++iTer ) delete iTer->second; fsFactories.clear(); } G4RotationMatrix* GeoFactory::DirectionToRotation( const G4ThreeVector& direction ) { const double yAngle = (-1.0)*atan2( direction.x(), direction.z() ); const double xAngle = atan2( direction.y(), sqrt( direction.x() * direction.x() + direction.z() * direction.z() ) ); G4RotationMatrix* rotation = new G4RotationMatrix(); //Deleted by Magic :) rotation->rotateY( yAngle ); rotation->rotateX( xAngle ); rotation->rotateZ( 0.0 ); return rotation; } G4VisAttributes* GeoFactory::LoadVisualisation( DBLinkPtr table ) { G4VisAttributes* visAttribs = new G4VisAttributes(); // Deleted by Geant4 try // Optional visualisation color { const vector& color = table->GetDArray( "vis_color" ); if( color.size() == 3 ) // RGB visAttribs->SetColour( G4Colour( color[0], color[1], color[2] ) ); else if( color.size() == 4 ) // RGBA visAttribs->SetColour( G4Colour( color[0], color[1], color[2], color[3] ) ); else Log::Die( "GeoFactory::LoadVisualisationAttribs malformed vis_color field in table " + table->GetIndex() ); } catch (DBNotFoundError &e) { }; try // Optional visualisation style { const string visStyle = table->GetS( "vis_style" ); if( visStyle == "wireframe" ) visAttribs->SetForceWireframe( true ); else if( visStyle == "solid" ) visAttribs->SetForceSolid( true ); else Log::Die( "GeoFactory::LoadVisualisationAttribs malformed vis-style field in table " + table->GetIndex() ); } catch (DBNotFoundError &e) { }; try // Optional edges { if( table->GetI( "vis_auxedge" ) == 1 ) visAttribs->SetForceAuxEdgeVisible( true ); } catch (DBNotFoundError &e) { }; try // Optional visualisation visibility { if( table->GetI("vis_invisible") == 1 ) visAttribs->SetVisibility( false ); } catch (DBNotFoundError &e) { }; try // Optional simple visibility i.e. daughters are invisible { if( table->GetI("vis_simple") == 1 ) visAttribs->SetDaughtersInvisible( true ); } catch (DBNotFoundError &e) { }; return visAttribs; } pair GeoFactory::LoadTranslation( DBLinkPtr table ) { G4RotationMatrix* rotation = NULL; // Rotation is optional, default is no rotation. try { const vector& rotVector = table->GetDArray( "rotation" ); rotation = new G4RotationMatrix(); // Geant4 deletes this rotation->rotateX( rotVector[0] * deg ); rotation->rotateY( rotVector[1] * deg ); rotation->rotateZ( rotVector[2] * deg ); } catch( DBNotFoundError& e ) { rotation = NULL; } try { const vector& direction = table->GetDArray( "direction" ); if( rotation != NULL ) warn << "GeoFactory::LoadTranslation rotation and direction defined, direction used." << newline; rotation = DirectionToRotation( G4ThreeVector( direction[0], direction[1], direction[2] ) ); } catch( DBNotFoundError& e ) { /* Not a problem */ } try { const double zRot = table->GetD( "roll" ); if( rotation == NULL ) rotation = new G4RotationMatrix(); // Geant4 deletes this rotation->rotateZ( zRot * deg ); } catch( DBNotFoundError& e ) { /* Not a problem */ } G4ThreeVector position( 0.0, 0.0, 0.0 ); // Position is optional, default is centre of mother try { const vector& posVector = table->GetDArray( "position" ); position.setX( posVector[0] * mm ); position.setY( posVector[1] * mm ); position.setZ( posVector[2] * mm ); } catch( DBNotFoundError& e ) { } // Now correct these by this volumes' relative (if it exists) try { const string relative = table->GetS( "relative" ); G4VPhysicalVolume* relativeVol = Detector::FindPhysicalVolume( relative ); if( relativeVol == NULL ) Log::Die( "GeoFactory::LoadTranslation: No relative " + relative + " exists." ); if( rotation != NULL ) { *rotation *= *relativeVol->GetFrameRotation(); } // believe this line to be cause of bug that shifts the relative volumes in the wrong direction. (JW 14-11-2017) // position += relativeVol->GetFrameTranslation(); position -= relativeVol->GetFrameTranslation(); } catch( DBNotFoundError& e ) { /* Optional, not a problem */ } return pair( position, rotation ); } pair GeoFactory::SplitSolid( G4VSolid* solid, const std::string& name, const double zSplit ) { pair solids; // Now calculate the bounding box, in local coordinates (to solid) double x0, y0, z0, x1, y1, z1; { G4VoxelLimits voxelLimits; // Defaults to "infinite" limits. G4AffineTransform affineTransform; // Defaults to no transform solid->CalculateExtent(kXAxis, voxelLimits, affineTransform, x0,x1); solid->CalculateExtent(kYAxis, voxelLimits, affineTransform, y0,y1); solid->CalculateExtent(kZAxis, voxelLimits, affineTransform, z0,z1); } if( zSplit < z0 || zSplit > z1 ) Log::Die( "RAT::geo::SplitSolid Split z coordinate outside of solid volume." ); // Add the top { const double sizeZ = fabs( z1 - zSplit ); vector size; size.push_back( fabs( x1 - x0 ) / 2.0 ); // Half heights for Box size.push_back( fabs( y1 - y0 ) / 2.0 ); // Half heights for Box size.push_back( sizeZ / 2.0 ); // Half heights for Box G4VSolid* box = new G4Box( "box", size[0] * mm, size[1] * mm, size[2] * mm ); solids.first = new G4IntersectionSolid( name + "_top", solid, box, NULL, G4ThreeVector( 0, 0, zSplit + sizeZ / 2.0 ) ); } // Add the bottom { const double sizeZ = fabs( z0 - zSplit ); vector size; size.push_back( fabs( x1 - x0 ) / 2.0 ); // Half heights for Box size.push_back( fabs( y1 - y0 ) / 2.0 ); // Half heights for Box size.push_back( sizeZ / 2.0 ); // Half heights for Box G4VSolid* box = new G4Box( "box", size[0] * mm, size[1] * mm, size[2] * mm ); solids.second = new G4IntersectionSolid( name + "_bottom", solid, box, NULL, G4ThreeVector( 0, 0, zSplit - sizeZ / 2.0 ) ); } return solids; } }