BLCoordinates.hh

Go to the documentation of this file.
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
g4beamline