00001 // BLCoordinates.hh 00002 /* 00003 This source file is part of G4beamline, http://g4beamline.muonsinc.com 00004 Copyright (C) 2003,2004,2005,2006 by Tom Roberts, all rights reserved. 00005 00006 This program is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU General Public License 00008 as published by the Free Software Foundation; either version 2 00009 of the License, or (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 http://www.gnu.org/copyleft/gpl.html 00017 */ 00018 00019 #ifndef BLCOORDINATES_HH 00020 #define BLCOORDINATES_HH 00021 00022 #include <vector> 00023 #include "G4Allocator.hh" 00024 #include "G4Track.hh" 00025 #include "G4ThreeVector.hh" 00026 #include "G4RotationMatrix.hh" 00027 #include "G4VUserTrackInformation.hh" 00028 #include "G4UserTrackingAction.hh" 00029 #include "G4UserSteppingAction.hh" 00030 #include "BLCoordinateTransform.hh" 00031 #include "BLManager.hh" 00032 00033 /** BLCoordinateType enumerates the coordinate systems. 00034 **/ 00035 enum BLCoordinateType {BLCOORD_GLOBAL, BLCOORD_CENTERLINE, BLCOORD_REFERENCE}; 00036 00037 /** class BLCoordinates manages the centerline coordinates. 00038 * 00039 * Whenever an element is placed into the world group, the current 00040 * centerline coordinates are normally used, rather than global 00041 * coordinates (the local coordinates of the world volume/group). 00042 * 00043 * Centerline coordinates are X,Y,Z, with Z along the nominal beam 00044 * direction, X is beam left, and Y is beam up. The centerline itself 00045 * is always X=0,Y=0, and consists of a sequence of segmentCLs each of 00046 * which is straight, and the centerline is continuous at each 00047 * corner (bend in the centerline). Except within bending magnets 00048 * the reference particle is supposed to travel directly down the 00049 * centerline. Z is continuous along the centerline, including at 00050 * corners; the first segmentCL extends to Z=-infinity, and the last 00051 * segmentCL extends to Z=+infinity. 00052 * 00053 * Note that the coordinate transform global->centerline is NOT unique 00054 * -- near corners both segmentCLs may refer to a given point. The 00055 * transform centerline->global is unique for a given segmentCL. The 00056 * centerline itself is continuous at corners, but tracks will in 00057 * general have a discontinuity in their centerline coordinates when 00058 * transitioning from one segmentCL to the next. A track will transition 00059 * from one segmentCL to the next when either its Z coordinate exceeds 00060 * that of the initial segmentCL's end (corner), or when its radius 00061 * exceeds the radiusCut for the initial segmentCL. 00062 * 00063 * Initially the centerline coordinates are identical to global 00064 * coordinates. The start() function will change the starting location 00065 * and orientation of the first segmentCL, and the corner() function ends 00066 * the current segmentCL and begins a new one. start() must not be called 00067 * after any element has been placed in the first segmentCL, or after 00068 * corner() has been called. 00069 * 00070 * Instances of this class represent the current centerline coordinates 00071 * of a track, and are linked into the track via 00072 * G4Track::SetUserInformation() (an instance is registered with 00073 * BLManager to manage the instance linked into the track, 00074 * and they can also be used for individual points, if necessary). 00075 * Static members and functions are used to access and create the 00076 * centerline segmentCLs. 00077 * 00078 * Because of the need to transition tracks from one segmentCL to the 00079 * next, corners with acute angles are prohibited. 00080 * 00081 * NOTE: BLManager expects G4Track::GetUserInformation() to return a 00082 * pointer to a BLCoordinates object, or to an object of a class derived 00083 * from it. This means that any G4VUserTrackInformation class used in 00084 * a simulation using BLManager should be derived from this class, and not 00085 * directly from G4VUserTrackInformation (but verify is used to detect 00086 * if it is not a BLCoordinates object). 00087 * 00088 * Note the BLManager::UserSteppingAction() manages the updates to the 00089 * current track's BLCoordinates before doing anything else. 00090 * 00091 * NOTE: "CL" in a vairable means it is for centerline coordinates; 00092 * "RC" means it is for reference coordinates. 00093 **/ 00094 class BLCoordinates : public G4VUserTrackInformation { 00095 enum { VERIFY=0x13579246 }; 00096 int verify; 00097 unsigned int segmentCL; 00098 unsigned int segmentRC; 00099 BLCoordinateType prevType; 00100 G4double global[4]; 00101 G4double centerline[4]; 00102 G4double reference[4]; 00103 int segmentCLRadiusFailure; 00104 G4bool findCLSegment(const G4double _global[4]); 00105 static G4Allocator<BLCoordinates> allocator; 00106 public: 00107 /// Default constructor -- for UserSteppingAction or without point. 00108 BLCoordinates(); 00109 00110 /// Constructor -- finds the earliest segmentCL containing the point 00111 /// (global coordinates). 00112 BLCoordinates(const G4double _global[4]); 00113 00114 /// Destructor. 00115 virtual ~BLCoordinates() { } 00116 00117 /// operator new - using G4Allocator. 00118 /// NOTE: any derived class MUST re-implement this. 00119 void *operator new(size_t) { 00120 return (void *)allocator.MallocSingle(); 00121 } 00122 00123 /// operator delete - using G4Allocator. 00124 /// NOTE: any derived class MUST re-implement this. 00125 void operator delete(void *p) { 00126 allocator.FreeSingle((BLCoordinates *)p); 00127 } 00128 00129 /// isValid() verifies that this is a valid BLCoordinates instance. 00130 /// NOTE: this is not virtual, and cannot be made virtual! 00131 G4bool isValid() const; 00132 00133 /// setGlobal() updates the centerline coordinates for the new point[] 00134 /// of the track; uses the current segmentCL #, and will update it if 00135 /// the track crosses into a new segmentCL. 00136 /// returns false if the track fails radiusCut in its current and 00137 /// next segmentCL (or all segmentCL if ring is true). 00138 /// Also updates reference coordinates, if validRC is true and the 00139 /// centerline radiusCut succeeded. 00140 G4bool setGlobal(const G4double _global[4]); 00141 G4bool setGlobal(const G4ThreeVector &pos, G4double time); 00142 00143 /// getCenterlineCoords() returns the centerline coordinates. 00144 /// DEPRECATED: use getCoords() instead. 00145 void getCenterlineCoords(G4double local[4]) const 00146 { local[0]=centerline[0]; local[1]=centerline[1]; 00147 local[2]=centerline[2]; local[3]=centerline[3]; } 00148 void getCenterlineCoords(G4ThreeVector& local) const 00149 { local[0]=centerline[0]; local[1]=centerline[1]; 00150 local[2]=centerline[2]; } 00151 00152 /// getCoords() returns the appropriate coordinate values. 00153 void getCoords(BLCoordinateType type, G4double local[4]); 00154 void getCoords(BLCoordinateType type, G4ThreeVector &local); 00155 00156 /// getCLZ() returns the centerline z coordinate. 00157 G4double getCLZ() { return centerline[2]; } 00158 00159 /// getRotation() returns the appropriate coordinate rotation for 00160 /// the previous call to getCoords(). 00161 /// Given a G4ThreeVector B in global coordinates, this transforms 00162 /// it to centerline components: 00163 /// coord->getCoords(BLCOORD_CENTERLINE,local); 00164 /// B = coord->getRotation() * B; 00165 G4RotationMatrix &getRotation() { return getRotation(prevType); } 00166 00167 /// getRotation() returns the rotation for the specified coordinates. 00168 /// Given a G4ThreeVector B in global coordinates, this transforms 00169 /// it to centerline components: 00170 /// B = coord->getRotation(BLCOORD_CENTERLINE) * B; 00171 G4RotationMatrix &getRotation(BLCoordinateType type); 00172 00173 /// getCenterlineRotation() returns the rotation matrix used for the 00174 /// last setGlobal() of this instance. This is the rotation of 00175 /// the centerline wrt global coordinate axes. 00176 /// DEPRECATED -- use getRotation(). 00177 G4RotationMatrix getCenterlineRotation() { 00178 if(segmentCL >= segmentCLVector.size()) 00179 return G4RotationMatrix(); 00180 return segmentCLVector[segmentCL].transform.getRotationInverse(); 00181 } 00182 00183 /// getCurrentRadiusCut() returns the radiusCut for the current CL 00184 /// segment. 00185 static double getCurrentRadiusCut() { 00186 if(currentCL >= segmentCLVector.size()) 00187 return DBL_MAX; 00188 else 00189 return segmentCLVector[currentCL].radiusCut; 00190 } 00191 00192 /// getTransformRotation() returns the rotation matrix of the 00193 /// global -> centerline coordinate transformation; it is the 00194 /// inverse of getCenterlineRotation(). 00195 /// Given a G4ThreeVector B in global coordinates, this transforms 00196 /// it to centerline components: 00197 /// B = getTransformRotation() * B; 00198 /// DEPRECATED -- use getRotation(). 00199 G4RotationMatrix getTransformRotation() { 00200 if(segmentCL >= segmentCLVector.size()) 00201 return G4RotationMatrix(); 00202 return segmentCLVector[segmentCL].transform.getRotation(); 00203 } 00204 00205 /// getSegmentCL() re turns the CL segment # (for debugging). 00206 int getSegmentCL() { return segmentCL; } 00207 00208 /// update() 00209 /// This function ensures that a UserTrackInformation object is 00210 /// linked into the track; if none is, it creates a new 00211 /// BLCoordinates instance and links it in. It also calls setGlobal() 00212 /// for the BLCoordinates linked into the track. 00213 static void update(G4Track *track); 00214 00215 /// Print from G4VUserTrackInformation. 00216 virtual void Print() const { } 00217 00218 // static variables and functions to define and manipulate segmentCLs. 00219 // NOTE: these routines must all be called before the first instance 00220 // is created. That is, the centerline must be completely laid out 00221 // before any tracks are created. 00222 private: 00223 enum State { UNUSED, CONSTRUCTING, TRACKING }; 00224 struct CLSegment { 00225 G4double minZ; 00226 G4double maxZ; 00227 G4double radiusCut; 00228 BLCoordinateTransform transform; 00229 unsigned int firstRCSegment; 00230 CLSegment(G4double _minZ, G4double _maxZ, G4double _radiusCut, 00231 const BLCoordinateTransform &_transform) : 00232 transform(_transform) 00233 { minZ=_minZ; maxZ=_maxZ; radiusCut=_radiusCut; 00234 firstRCSegment=99999999; } 00235 friend class BLCoordinates; 00236 }; 00237 static std::vector<CLSegment> segmentCLVector; 00238 static unsigned currentCL; 00239 static G4bool ring; 00240 static State state; 00241 static G4bool steppingVerbose; 00242 static void init(); 00243 public: 00244 /// start() sets the starting point and direction for the 00245 /// first segmentCL. Must not be called after corner() is 00246 /// called, or after any element has been placed using centerline 00247 /// coordinates. point[] is in global coordinates, z is the starting 00248 /// value of z in CENTERLINE coordinates, _ring indicates whether 00249 /// a ring is present (so jumps in segmentCL # are permitted), and 00250 /// rotation should be the rotation of the first segmentCL's 00251 /// centerline wrt the global coordinate axes (i.e. it is an 00252 /// active rotation of the centerline as an object wrt the global 00253 /// coordinate axes). 00254 static void start(const G4double point[4], G4double z, 00255 G4RotationMatrix *rotation=0, G4double radiusCut=0.0, 00256 G4bool _ring=false); 00257 00258 /// corner() creates a corner in the centerline by ending the 00259 /// current segmentCL and beginning a new one. z is the position 00260 /// in CENTERLINE coordinates of the current segmentCL, and rotation 00261 /// is relative to the current CENTERLINE coordinates (i.e. as an 00262 /// active rotation of the centerline as an object wrt the CENTERLINE 00263 /// coordinate axes of the current segmentCL). z must be greater than 00264 /// the centerline z of the previous corner or start. rotation can be 00265 /// an identity matrix (e.g. to merely set a new radiusCut). 00266 static void corner(G4double z, G4RotationMatrix *rotation, 00267 G4double radiusCut); 00268 00269 /// getCurrentTransform() returns the current BLCoordinateTransform 00270 /// for the centerline coordinates (i.e. the coordinate transform 00271 /// global->centerline of the current segmentCL). 00272 static BLCoordinateTransform &getCurrentTransform(); 00273 00274 /// getCurrentRotation() returns the current G4RotationMatrix for 00275 /// the centerline coordinates (i.e. the active rotation of the 00276 /// current segmentCL, as an object rotated wrt global coordinate 00277 /// axes). 00278 /// Given a G4ThreeVector B in global coordinates, this transforms 00279 /// it to centerline components: 00280 /// B = *getCurrentRotation() * B; 00281 static G4RotationMatrix *getCurrentRotation(); 00282 00283 /// getCurrentGlobal() returns global coordinates from centerline coordinates, 00284 /// using the current segmentCL. 00285 static void getCurrentGlobal(const G4double local[4], G4double _global[4]); 00286 00287 /// getCurrentGlobal() returns global coordinates from centerline coordinates, 00288 /// using the current segmentCL. 00289 static void getCurrentGlobal(const G4ThreeVector& local, G4ThreeVector& _global); 00290 00291 /// getGlobalAnywhere() returns global coordinates from centerline 00292 /// coordinates, using the lowest segmentCL containing local. 00293 static void getGlobalAnywhere(const G4ThreeVector& local, 00294 G4ThreeVector& _global); 00295 00296 /// getGlobalRotation() returns the local->global rotation matrix 00297 /// coordinates, using the lowest segmentCL containing local. 00298 static G4RotationMatrix *getGlobalRotation(const G4ThreeVector& local); 00299 00300 /// getRadiusCut() returns the radius cut for the lowest 00301 /// segmentCL containing local. 00302 static G4double getRadiusCut(const G4ThreeVector& local); 00303 00304 /// getCoordinateType() converts a G4String name to a 00305 /// BLCoordinateType. Names are: global, centerline, reference; 00306 /// only the first letter is used, case insensitive. 00307 /// Also enables the generation of REference Coordinates, if they 00308 /// are selected by s. 00309 static BLCoordinateType getCoordinateType(G4String s); 00310 00311 // static variables and function to manipulate segmentRC-s. 00312 // NOTE: reference coordinates can easily get onto the wrong segment. 00313 // This is best avoided by restricting the beam to a small radius from 00314 // the reference track so that ambiguities are avoided. But that is 00315 // not always possible (e.g. in a helical cooling channel) -- in that 00316 // case it is best to start tracking in a sement where the reference 00317 // particle is close to the centerline. 00318 // 00319 // updateReferenceCoordinates() always sets segmentRC to the highest 00320 // segment N such that Z<=seg[N].maxZ; it could have Z<seg[N].minZ 00321 // but will have Z>seg[N-1].maxZ (here Z is evaluated for each seg[]). 00322 // 00323 // In the plane of two successive segments N and N+1, there is a 00324 // triangle with Z>seg[N].maxZ and Z<seg[N+1].minZ on the outside of 00325 // the bend; there is also a triangle valid for both segments. This 00326 // is handled by creating an interpolation transform between every 00327 // pair of segments; seg[N-1].interpolate is used when 00328 // Z<seg[N].interpolatePrev, and seg[N].interpolate is used when 00329 // Z>seg[N].interpolateThis (1/4 and 3/4 along the segment in Z). 00330 // The interpolation covers the entire omitted triangle, and much 00331 // of the overlap triangle (especially near the reference track). 00332 // 00333 // updateReferenceCoordinates() must keep up as the Track is tracked, 00334 // but the interpolation is performed only when the reference 00335 // coordinates are needed in getCoords(). 00336 // 00337 // correction accounts for curvature in the reference track, in which 00338 // case the reference path length is larger than the straight line 00339 // Segment. The difference is pro-rated in Z within the Segment, but 00340 // is ignored in X and Y (in keeping with the straight-line 00341 // approximation). Without this, values of Z would not be continuous, 00342 // and worse, Segment errors would occur near the downstream edge. 00343 private: 00344 struct RCSegment { 00345 G4double minZ; 00346 G4double maxZ; 00347 G4double correction; 00348 BLCoordinateTransform transform; 00349 G4double interpolatePrev; 00350 G4double interpolateThis; 00351 BLCoordinateTransform interpolate; 00352 RCSegment(G4double _minZ, G4double _maxZ, 00353 const BLCoordinateTransform &_transform, G4double corr, 00354 G4double _interpolatePrev, G4double _interpolateThis) 00355 : transform(_transform), interpolate(_transform) 00356 { minZ=_minZ; maxZ=_maxZ; correction=corr; 00357 interpolatePrev=_interpolatePrev; 00358 interpolateThis=_interpolateThis; } 00359 friend class BLCoordinates; 00360 }; 00361 static G4bool useRC; 00362 static G4bool validRC; 00363 static std::vector<RCSegment> segmentRCVector; 00364 static int currentRC; 00365 static G4double tolerance; 00366 static G4double mostRecentReferenceZ; 00367 class ReferenceCoordinates; 00368 int referenceCLsegment; // current CL segment of reference coords. 00369 BLCoordinateTransform *referenceTransformUsed; 00370 /// updateReferenceCoordinates() will update the reference coordinates, 00371 /// given the centerline coordintes are already updated and valid. 00372 /// Called by setGlobal(). 00373 void updateReferenceCoordinates(); 00374 public: 00375 /// useReferenceCoordinates() will arrange to fill segmentRCVector[] 00376 /// with reference coordinate segments as the reference particle is 00377 /// tracked. Must be called before the reference particle is tracked. 00378 /// Unless this is called, reference coordinates will not be available. 00379 /// Multiple calls are the same as one. 00380 static void useReferenceCoordinates(); 00381 00382 /// setMostRecentReferenceZ() sets the most recent z value of the 00383 /// reference coords. VALID ONLY WHILE TRACKING REFERENCE PARTICLE! 00384 static void setMostRecentReferenceZ(G4double z) 00385 { mostRecentReferenceZ = z; } 00386 00387 /// getMostRecentReferenceZ() returns the most recent z value of the 00388 /// reference coords. VALID ONLY WHILE TRACKING REFERENCE PARTICLE! 00389 static G4double getMostRecentReferenceZ() 00390 { return mostRecentReferenceZ; } 00391 }; 00392 00393 #endif // BLCOORDINATES_HH