Geant4-11
G4VFieldModel.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// Michael Kelsey 31 January 2019
27//
28// Class Description:
29//
30// Abstract base class to implement drawing vector field geometries
31// (e.g., electric, magnetic or gravity). Implementation extracted
32// from G4MagneticFieldModel, with field-value access left pure
33// virtual for implementation by base classes.
34
35#include "G4VFieldModel.hh"
36
37#include "G4ArrowModel.hh"
38#include "G4Colour.hh"
39#include "G4Field.hh"
40#include "G4FieldManager.hh"
41#include "G4PVPlacement.hh"
42#include "G4PVParameterised.hh"
43#include "G4Point3D.hh"
44#include "G4Polyline.hh"
45#include "G4SystemOfUnits.hh"
47#include "G4VGraphicsScene.hh"
48#include "G4VPhysicalVolume.hh"
49#include "G4VisAttributes.hh"
50
51#include <sstream>
52#include <limits>
53#include <vector>
54
55
56// Constructor and destructor
57
59
61(const G4String& typeOfField, const G4String& symbol,
62 const G4VisExtent& extentForField,
63 const std::vector<G4PhysicalVolumesSearchScene::Findings>& pvFindings,
64 G4int nDataPointsPerMaxHalfExtent,
65 Representation representation,
66 G4int arrow3DLineSegmentsPerCircle)
67: fExtentForField(extentForField)
68, fPVFindings(pvFindings)
69, fNDataPointsPerMaxHalfExtent(nDataPointsPerMaxHalfExtent)
70, fRepresentation(representation)
71, fArrow3DLineSegmentsPerCircle(arrow3DLineSegmentsPerCircle)
72, fTypeOfField(typeOfField)
73, fArrowPrefix(symbol)
74{
75 fType = "G4"+typeOfField+"FieldModel";
77
78 std::ostringstream oss;
82 oss << " whole scene";
83 } else {
84 oss
85 << ':' << fExtentForField.GetXmin()
86 << ':' << fExtentForField.GetXmax()
87 << ':' << fExtentForField.GetYmin()
88 << ':' << fExtentForField.GetYmax()
89 << ':' << fExtentForField.GetZmin()
90 << ':' << fExtentForField.GetZmax();
91 }
92 for (const auto& findings: fPVFindings) {
93 oss
94 << ',' << findings.fpFoundPV->GetName()
95 << ':' << findings.fFoundPVCopyNo;
96 }
97 if (fRepresentation == Representation::fullArrow) {
98 oss << " full arrow";
99 } else if (fRepresentation == Representation::lightArrow) {
100 oss << " light arrow";
101 }
102
103 fGlobalDescription = fType + oss.str();
104}
105
106
107// The main task of a model is to describe itself to the graphics scene.
108
110// G4cout << "G4VFieldModel::DescribeYourselfTo" << G4endl;
111
114 assert(tMgr);
116 assert(navigator);
117
118 G4FieldManager* globalFieldMgr = tMgr->GetFieldManager();
119 const G4Field* globalField = 0;
120 const G4String intro = "G4VFieldModel::DescribeYourselfTo: ";
121 if (globalFieldMgr) {
122 if (globalFieldMgr->DoesFieldExist()) {
123 globalField = globalFieldMgr->GetDetectorField();
124 if (!globalField) {
125 static G4bool warned = false;
126 if (!warned) {
127 G4cout << intro << "Null global field pointer." << G4endl;
128 warned = true;
129 }
130 }
131 }
132 } else {
133 static G4bool warned = false;
134 if (!warned) {
135 G4cout << intro << "No global field manager." << G4endl;
136 warned = true;
137 }
138 }
139
140 G4VisExtent extent = sceneHandler.GetExtent();
142 extent = sceneHandler.GetExtent();
143 } else {
144 extent = fExtentForField;
145 }
146 const G4double& xMin = extent.GetXmin();
147 const G4double& yMin = extent.GetYmin();
148 const G4double& zMin = extent.GetZmin();
149 const G4double& xMax = extent.GetXmax();
150 const G4double& yMax = extent.GetYmax();
151 const G4double& zMax = extent.GetZmax();
152 const G4double xHalfScene = 0.5 * (xMax - xMin);
153 const G4double yHalfScene = 0.5 * (yMax - yMin);
154 const G4double zHalfScene = 0.5 * (zMax - zMin);
155 const G4double xSceneCentre = 0.5 * (xMax + xMin);
156 const G4double ySceneCentre = 0.5 * (yMax + yMin);
157 const G4double zSceneCentre = 0.5 * (zMax + zMin);
158 const G4double maxHalfScene =
159 std::max(xHalfScene,std::max(yHalfScene,zHalfScene));
160 if (maxHalfScene <= 0.) {
161 G4cout << "Scene extent non-positive." << G4endl;
162 return;
163 }
164
165 // Constants
166 const G4double interval = maxHalfScene / fNDataPointsPerMaxHalfExtent;
167 const G4int nDataPointsPerXHalfScene = G4int(xHalfScene / interval);
168 const G4int nDataPointsPerYHalfScene = G4int(yHalfScene / interval);
169 const G4int nDataPointsPerZHalfScene = G4int(zHalfScene / interval);
170 const G4int nXSamples = 2 * nDataPointsPerXHalfScene + 1;
171 const G4int nYSamples = 2 * nDataPointsPerYHalfScene + 1;
172 const G4int nZSamples = 2 * nDataPointsPerZHalfScene + 1;
173 const G4int nSamples = nXSamples * nYSamples * nZSamples;
174 const G4double arrowLengthMax = 0.8 * interval;
175
176 // Working vectors for field values, etc.
177 std::vector<G4Point3D> Field(nSamples); // Initialises to (0,0,0)
178 std::vector<G4Point3D> xyz(nSamples); // Initialises to (0,0,0)
179 G4double FieldMagnitudeMax = -std::numeric_limits<G4double>::max();
180
181 // Get field values and ascertain maximum field.
182 for (G4int i = 0; i < nXSamples; i++) {
183 G4double x = xSceneCentre + (i - nDataPointsPerXHalfScene) * interval;
184
185 for (G4int j = 0; j < nYSamples; j++) {
186 G4double y = ySceneCentre + (j - nDataPointsPerYHalfScene) * interval;
187
188 for (G4int k = 0; k < nZSamples; k++) {
189 G4double z = zSceneCentre + (k - nDataPointsPerZHalfScene) * interval;
190
191 // Calculate indices into working vectors
192 const G4int ijk = i * nYSamples * nZSamples + j * nZSamples + k;
193 xyz[ijk].set(x,y,z);
194
195 G4ThreeVector pos(x,y,z);
196
197 // Check if point is in findings
198 if (!fPVFindings.empty()) {
199 G4bool isInPV = false;
200 for (const auto& findings: fPVFindings) {
201 G4VPhysicalVolume* pv = findings.fpFoundPV;
202 G4int copyNo = findings.fFoundPVCopyNo;
203 G4VSolid* solid = pv->GetLogicalVolume()->GetSolid();
204 G4PVParameterised* pvParam = dynamic_cast<G4PVParameterised*>(pv);
205 if (pvParam) {
206 auto* param = pvParam->GetParameterisation();
207 solid = param->ComputeSolid(copyNo,pvParam);
208 solid->ComputeDimensions(param,copyNo,pvParam);
209 }
210 // Transform point to local coordinate system
211 const auto& transform = findings.fFoundObjectTransformation;
212 auto rotation = transform.getRotation();
213 auto translation = transform.getTranslation();
214 G4ThreeVector lPos = pos; lPos -= translation; lPos.transform(rotation.invert());
215 if (solid->Inside(lPos)==kInside) {
216 isInPV = true;
217 break;
218 }
219 }
220 if (!isInPV) continue;
221 }
222 // Point is in findings - or there were no findings
223
224 // Find volume and field at this location.
225 const G4VPhysicalVolume* pPV =
226 navigator->LocateGlobalPointAndSetup(pos,0,false,true);
227 const G4Field* field = globalField;
228 if (pPV) {
229 // Get logical volume.
230 const G4LogicalVolume* pLV = pPV->GetLogicalVolume();
231 if (pLV) {
232 // Value for Region, if any, overrides
233 G4Region* pRegion = pLV->GetRegion();
234 if (pRegion) {
235 G4FieldManager* pRegionFieldMgr = pRegion->GetFieldManager();
236 if (pRegionFieldMgr) {
237 field = pRegionFieldMgr->GetDetectorField();
238 // G4cout << "Region with field" << G4endl;
239 }
240 }
241 // 'Local' value from logical volume, if any, overrides
242 G4FieldManager* pLVFieldMgr = pLV->GetFieldManager();
243 if (pLVFieldMgr) {
244 field = pLVFieldMgr->GetDetectorField();
245 // G4cout << "Logical volume with field" << G4endl;
246 }
247 }
248 }
249
250 G4double time = 0.; // FIXME: Can we get event time in some way?
251
252 // Subclasses will have implemented this for their own field
253 GetFieldAtLocation(field, xyz[ijk], time, Field[ijk]);
254
255 G4double mag = Field[ijk].mag();
256 if (mag > FieldMagnitudeMax) FieldMagnitudeMax = mag;
257 } // for (k, z
258 } // for (j, y
259 } // for (i, x
260
261 if (FieldMagnitudeMax <= 0.) {
262 G4cout << "No " << fTypeOfField << " field in this extent." << G4endl;
263 return;
264 }
265
266 for (G4int i = 0; i < nSamples; i++) {
267 const G4double Fmag = Field[i].mag();
268 const G4double f = Fmag / FieldMagnitudeMax;
269 if (f <= 0.) continue; // Skip zero field locations
270
271 G4double red = 0., green = 0., blue = 0., alpha = 1.;
272 if (f < 0.5) { // Linear colour scale: 0->0.5->1 is red->green->blue.
273 green = 2. * f;
274 red = 2. * (0.5 - f);
275 } else {
276 blue = 2. * (f - 0.5);
277 green = 2. * (1.0 - f);
278 }
279 const G4Colour arrowColour(red,green,blue,alpha);
280
281 // Very small arrows are difficult to see. Better to draw a line.
282 G4bool drawAsLine = false;
283 switch (fRepresentation) {
284 case Representation::fullArrow:
285 if (f < 0.1) {
286 drawAsLine = true;
287 }
288 break;
289 case Representation::lightArrow:
290 drawAsLine = true;
291 break;
292 default:
293 break;
294 }
295
296 // Head of arrow depends on field direction and strength...
297 G4double arrowLength = arrowLengthMax * f;
298 // ...but limit the length so it's visible.
299 if (f < 0.01) arrowLength = arrowLengthMax * 0.01;
300 const G4Point3D head = xyz[i] + arrowLength*Field[i]/Fmag;
301
302 if (drawAsLine) {
303 G4Polyline FArrowLite;
304 G4VisAttributes va(arrowColour);
305 va.SetLineWidth(2.);
306 FArrowLite.SetVisAttributes(va);
307 FArrowLite.push_back(xyz[i]);
308 FArrowLite.push_back(head);
309 sceneHandler.BeginPrimitives();
310 sceneHandler.AddPrimitive(FArrowLite);
311 sceneHandler.EndPrimitives();
312 } else {
313 G4ArrowModel FArrow(xyz[i].x(), xyz[i].y(), xyz[i].z(),
314 head.x(), head.y(), head.z(),
315 arrowLength/5, arrowColour,
316 fArrowPrefix+"Field",
318 FArrow.DescribeYourselfTo(sceneHandler);
319 }
320 } // for (i, nSamples
321}
static const G4double pos
static const G4double alpha
double G4double
Definition: G4Types.hh:83
bool G4bool
Definition: G4Types.hh:86
int G4int
Definition: G4Types.hh:85
#define G4endl
Definition: G4ios.hh:57
G4GLOB_DLL std::ostream G4cout
Hep3Vector & transform(const HepRotation &)
Definition: ThreeVectorR.cc:20
void DescribeYourselfTo(G4VGraphicsScene &) override
const G4Field * GetDetectorField() const
G4bool DoesFieldExist() const
G4VSolid * GetSolid() const
G4Region * GetRegion() const
G4FieldManager * GetFieldManager() const
G4VPVParameterisation * GetParameterisation() const
G4FieldManager * GetFieldManager() const
static G4TransportationManager * GetTransportationManager()
G4Navigator * GetNavigatorForTracking() const
G4FieldManager * GetFieldManager() const
G4String fArrowPrefix
virtual ~G4VFieldModel()
Representation fRepresentation
virtual void GetFieldAtLocation(const G4Field *field, const G4Point3D &position, G4double time, G4Point3D &result) const =0
G4int fNDataPointsPerMaxHalfExtent
G4String fTypeOfField
G4VisExtent fExtentForField
std::vector< G4PhysicalVolumesSearchScene::Findings > fPVFindings
virtual void DescribeYourselfTo(G4VGraphicsScene &sceneHandler)
G4int fArrow3DLineSegmentsPerCircle
G4VFieldModel(const G4String &typeOfField, const G4String &symbol="", const G4VisExtent &extentForField=G4VisExtent(), const std::vector< G4PhysicalVolumesSearchScene::Findings > &pvFindings=std::vector< G4PhysicalVolumesSearchScene::Findings >(), G4int nDataPointsPerHalfScene=10, Representation representation=Representation::fullArrow, G4int arrow3DLineSegmentsPerCircle=6)
virtual void BeginPrimitives(const G4Transform3D &objectTransformation=G4Transform3D())=0
virtual void AddPrimitive(const G4Polyline &)=0
virtual const G4VisExtent & GetExtent() const
virtual void EndPrimitives()=0
G4String fGlobalDescription
Definition: G4VModel.hh:100
G4String fType
Definition: G4VModel.hh:98
G4String fGlobalTag
Definition: G4VModel.hh:99
G4LogicalVolume * GetLogicalVolume() const
virtual EInside Inside(const G4ThreeVector &p) const =0
virtual void ComputeDimensions(G4VPVParameterisation *p, const G4int n, const G4VPhysicalVolume *pRep)
Definition: G4VSolid.cc:137
void SetLineWidth(G4double)
static const G4VisExtent & GetNullExtent()
Definition: G4VisExtent.cc:60
G4double GetYmin() const
Definition: G4VisExtent.hh:101
G4double GetXmax() const
Definition: G4VisExtent.hh:100
G4double GetYmax() const
Definition: G4VisExtent.hh:102
G4double GetZmax() const
Definition: G4VisExtent.hh:104
G4double GetZmin() const
Definition: G4VisExtent.hh:103
G4double GetXmin() const
Definition: G4VisExtent.hh:99
void SetVisAttributes(const G4VisAttributes *)
Definition: G4Visible.cc:96
@ kInside
Definition: geomdefs.hh:70
T max(const T t1, const T t2)
brief Return the largest of the two arguments
G4bool transform(G4String &input, const G4String &type)