Files
uLib/src/HEP/Geant/Solid.cpp

225 lines
6.7 KiB
C++

/*//////////////////////////////////////////////////////////////////////////////
// CMT Cosmic Muon Tomography project //////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
Copyright (c) 2014, Universita' degli Studi di Padova, INFN sez. di Padova
All rights reserved
Authors: Andrea Rigoni Garola < andrea.rigoni@pd.infn.it >
------------------------------------------------------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3.0 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library.
//////////////////////////////////////////////////////////////////////////////*/
// G4 Solid //
#include <CLHEP/Units/SystemOfUnits.h>
#include <Geant4/G4LogicalVolume.hh>
#include <Geant4/G4Material.hh>
#include <Geant4/G4NistManager.hh>
// Tessellated solid //
#include <Geant4/G4TessellatedSolid.hh>
#include <Geant4/G4ThreeVector.hh>
#include <Geant4/G4TriangularFacet.hh>
#include <Geant4/G4Box.hh>
#include <Geant4/G4PVPlacement.hh>
#include "Math/Dense.h"
#include "Math/Transform.h"
#include "Solid.h"
namespace uLib {
namespace Geant {
class DetectorsSolidImpl {
public:
static G4ThreeVector getG4Vector3f(const Vector3f &vector) {
return G4ThreeVector(vector(0), vector(1), vector(2));
}
};
Solid::Solid()
: m_Name("unnamed_solid"), m_Material(NULL), m_Logical(NULL), m_Physical(NULL),
m_Position(new G4ThreeVector(0,0,0)), m_Rotation(NULL) {}
Solid::Solid(const char *name)
: m_Name(name), m_Material(NULL), m_Logical(NULL), m_Physical(NULL),
m_Position(new G4ThreeVector(0,0,0)), m_Rotation(NULL) {}
Solid::~Solid() {
if (m_Position) delete m_Position;
if (m_Rotation) delete m_Rotation;
}
void Solid::SetNistMaterial(const char *name) {
G4NistManager *nist = G4NistManager::Instance();
G4Material *mat = nist->FindOrBuildMaterial(name);
if (mat) SetMaterial(mat);
}
void Solid::SetMaterial(G4Material *material) {
if (material) {
m_Material = material;
if (m_Logical) {
m_Logical->SetMaterial(material);
} else if (GetG4Solid()) {
m_Logical = new G4LogicalVolume(GetG4Solid(), m_Material, GetName());
}
}
}
void Solid::SetTransform(Matrix4f transform) {
uLib::AffineTransform t;
t.SetMatrix(transform);
// 2. Extract position and rotation for Geant4
Vector3f pos = t.GetPosition();
if (!m_Position) m_Position = new G4ThreeVector();
*m_Position = G4ThreeVector(pos(0), pos(1), pos(2));
// Create a G4 rotation matrix from the 4x4 matrix
Matrix3f m = t.GetRotation();
if (!m_Rotation) m_Rotation = new G4RotationMatrix();
m_Rotation->set(G4ThreeVector(m(0,0), m(1,0), m(2,0)),
G4ThreeVector(m(0,1), m(1,1), m(2,1)),
G4ThreeVector(m(0,2), m(1,2), m(2,2)));
// 3. If object is already placed, update its transformation
if (m_Physical) {
m_Physical->SetTranslation(*m_Position);
m_Physical->SetRotation(m_Rotation);
}
}
void Solid::SetParent(Solid *parent) {
if (!m_Logical) {
std::cerr << "logical volume not created for solid " << GetName() << std::endl;
return;
}
if(m_Physical) {
std::cerr << "physical volume already created for solid " << GetName() << std::endl;
return;
}
G4LogicalVolume* parentLogical = nullptr;
if (parent) {
parentLogical = parent->GetLogical();
if (!parentLogical) {
std::cerr << "parent logical volume not created for solid " << parent->GetName() << std::endl;
return;
}
}
// G4PVPlacement
m_Physical = new G4PVPlacement(
m_Rotation, // Rotation
*m_Position, // Position (translation) inside the parent
m_Logical, // The logical volume of this solid (the child)
GetName(), // Name of the physical volume
parentLogical, // The logical volume of the parent (nullptr if it's the World volume)
false, // Boolean operations (usually false)
0, // Copy number
true // Check overlaps (useful to enable in debug phase)
);
}
TessellatedSolid::TessellatedSolid()
: BaseClass("unnamed_tessellated"), m_Solid(new G4TessellatedSolid("unnamed_tessellated")) {}
TessellatedSolid::TessellatedSolid(const char *name)
: BaseClass(name), m_Solid(new G4TessellatedSolid(name)) {
}
void TessellatedSolid::SetMesh(TriangleMesh &mesh) {
this->m_Mesh = mesh;
G4TessellatedSolid *ts = this->m_Solid;
for (int i = 0; i < mesh.Triangles().size(); ++i) {
const Vector3i &trg = mesh.Triangles().at(i);
G4TriangularFacet *facet = new G4TriangularFacet(
DetectorsSolidImpl::getG4Vector3f(mesh.Points().at(trg(0))),
DetectorsSolidImpl::getG4Vector3f(mesh.Points().at(trg(1))),
DetectorsSolidImpl::getG4Vector3f(mesh.Points().at(trg(2))), ABSOLUTE);
ts->AddFacet((G4VFacet *)facet);
}
if (this->m_Logical) {
this->m_Logical->SetSolid(ts);
}
}
void TessellatedSolid::Update() {
}
BoxSolid::BoxSolid(const char *name) :
BaseClass(name),
m_ContainerBox(new ContainerBox()),
m_Solid(new G4Box(name, 1, 1, 1))
{}
BoxSolid::BoxSolid(const char *name, ContainerBox *box) : BaseClass(name) {
m_Solid = new G4Box(name, 1, 1, 1);
m_ContainerBox = box;
Object::connect(box, &ContainerBox::Updated, this, &BoxSolid::Update);
if (m_Logical) {
m_Logical->SetSolid(m_Solid);
}
Update();
}
void BoxSolid::Update() {
if (m_ContainerBox) {
Vector3f size = m_ContainerBox->GetSize();
m_Solid->SetXHalfLength(size(0) * 0.5);
m_Solid->SetYHalfLength(size(1) * 0.5);
m_Solid->SetZHalfLength(size(2) * 0.5);
// Geant4 placement is relative to center. uLib Box is anchored at corner.
// 1. Get position and rotation (clean, without scale)
Vector3f pos = m_ContainerBox->GetPosition();
Matrix3f rot = m_ContainerBox->GetRotation();
// 2. Center = Corner + Rotation * (Half-Size)
// We must rotate the offset vector because uLib box can be rotated.
Vector3f center = pos + rot * (size * 0.5);
uLib::AffineTransform t;
t.SetPosition(center);
t.SetRotation(rot);
this->SetTransform(t.GetMatrix());
}
}
} // namespace Geant
} // namespace uLib