/scratch0/jsnuveri/BDSIM/BDSIMgit/bdsim/src/BDSMagnetOuterFactoryPolesBase.cc

00001 #include "BDSMagnetOuterFactoryPolesBase.hh"
00002 
00003 #include "BDSBeamPipe.hh"
00004 #include "BDSDebug.hh"
00005 #include "BDSExecOptions.hh"
00006 #include "BDSGeometryComponent.hh"
00007 #include "BDSGlobalConstants.hh"
00008 #include "BDSMagnetColours.hh"
00009 #include "BDSMagnetOuterFactoryCylindrical.hh" // for default geometry
00010 #include "BDSMaterials.hh"
00011 #include "BDSSDManager.hh"
00012 // #include "BDSUtilities.hh"                 // for calculateorientation - s and r bend
00013 
00014 #include "globals.hh"                      // geant4 globals / types
00015 #include "G4Box.hh"
00016 #include "G4Colour.hh"
00017 #include "G4EllipticalTube.hh"
00018 #include "G4LogicalVolume.hh"
00019 #include "G4Material.hh"
00020 #include "G4PVPlacement.hh"
00021 #include "G4SubtractionSolid.hh"
00022 #include "G4ThreeVector.hh"
00023 #include "G4Tubs.hh"
00024 #include "G4UnionSolid.hh"
00025 #include "G4UserLimits.hh"
00026 #include "G4VisAttributes.hh"
00027 #include "G4VSolid.hh"
00028 
00029 #include <cmath>
00030 #include <utility>                         // for std::pair
00031 #include <algorithm>                       // for std::max
00032 
00033 BDSMagnetOuterFactoryPolesBase::BDSMagnetOuterFactoryPolesBase()
00034 {
00035   // geometrical parameters
00036   poleFraction        = 0.7;
00037   poleAngularFraction = 0.45;
00038   poleTipFraction     = 0.2;
00039 
00040   // now the base class constructor should be called first which
00041   // should call clean up (in the derived class) which should initialise
00042   // the variables I think, but doing here just to be sure.
00043   CleanUp();
00044 }
00045 
00046 void BDSMagnetOuterFactoryPolesBase::CleanUp()
00047 {
00048   BDSMagnetOuterFactoryBase::CleanUp();
00049   
00050   poleStartRadius  = 0;
00051   poleFinishRadius = 0;
00052   yokeStartRadius  = 0;
00053   yokeFinishRadius = 0;
00054 }
00055 
00056 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateSectorBend(G4String      name,
00057                                                                        G4double      length,
00058                                                                        BDSBeamPipe*  beamPipe,
00059                                                                        G4double      outerDiameter,
00060                                                                        G4double      angle,
00061                                                                        G4Material*   outerMaterial)
00062 {
00063 #ifdef BDSDEBUG
00064   G4cout << __METHOD_NAME__ << G4endl;
00065 #endif
00066   CleanUp(); // doesn't use CommonConstructor so must do this manually
00067   
00068   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateSectorBend(name,length,beamPipe,outerDiameter,
00069                                                                         angle,outerMaterial);
00070   /*
00071 
00072   // test input parameters - set global options as default if not specified
00073   TestInputParameters(beamPipe,outerDiameter,outerMaterial);
00074 
00075   G4int orientation   = BDS::CalculateOrientation(angle);
00076   G4double zcomponent = cos(fabs(angle*0.5)); // calculate components of normal vectors (in the end mag(normal) = 1)
00077   G4double xcomponent = sin(fabs(angle*0.5)); // note full angle here as it's the exit angle
00078   G4ThreeVector inputface  = G4ThreeVector(-orientation*xcomponent, 0.0, -1.0*zcomponent); //-1 as pointing down in z for normal
00079   G4ThreeVector outputface = G4ThreeVector(-orientation*xcomponent, 0.0, zcomponent);   // no output face angle
00080   
00081   if (beamPipe->ContainerIsCircular())
00082     {
00083       //circular beampipe so we can simply use its radius
00084       outerSolid = new G4CutTubs(name + "_outer_solid",       // name
00085                                  beamPipe->GetContainerRadius() + 2*lengthSafety,  // inner radius
00086                                  outerDiameter*0.5,                 // outer radius
00087                                  length*0.5-2*lengthSafety,   // half length
00088                                  0,                           // rotation start angle
00089                                  CLHEP::twopi,                // rotation finish angle
00090                                  inputface,                   // input face normal
00091                                  outputface);                 // output face normal
00092 
00093       //container is similar but slightly wider and hollow (to allow placement of beampipe)
00094       containerSolid = new G4CutTubs(name + "_contiainer_solid",  // name
00095                                      beamPipe->GetContainerRadius() + lengthSafety, // inner radius
00096                                      outerDiameter*0.5 + lengthSafety,  // outer radius
00097                                      length*0.5,                  // half length
00098                                      0,                           // rotation start angle
00099                                      CLHEP::twopi,                // rotation finish angle
00100                                      inputface,                   // input face normal
00101                                      outputface);                 // output face normal
00102     }
00103   else
00104     {
00105       G4VSolid* outerSolidCylinder = new G4CutTubs(name + "_outer_solid_cylinder",  // name
00106                                                    0,  // inner radius - for unambiguous subtraction
00107                                                    outerDiameter*0.5,                 // outer radius
00108                                                    length*0.5-2*lengthSafety,   // half length
00109                                                    0,                           // rotation start angle
00110                                                    CLHEP::twopi,                // rotation finish angle
00111                                                    inputface,                   // input face normal
00112                                                    outputface);                 // output face normal
00113       outerSolid = new G4SubtractionSolid(name + "_outer_solid",
00114                                           outerSolidCylinder,
00115                                           beamPipe->GetContainerSubtractionSolid());
00116 
00117       //container is similar but slightly wider
00118       G4VSolid* containerSolidCylinder = new G4CutTubs(name + "_container_solid_cylinder", // name
00119                                                        0,  // inner radius - for unambiguous subtraction
00120                                                        outerDiameter*0.5 + lengthSafety,  // outer radius
00121                                                        length*0.5,                  // half length
00122                                                        0,                           // rotation start angle
00123                                                        CLHEP::twopi,                // rotation finish angle
00124                                                        inputface,                   // input face normal
00125                                                        outputface);                 // output face normal
00126       containerSolid = new G4SubtractionSolid(name + "_container_solid",
00127                                               containerSolidCylinder,
00128                                               beamPipe->GetContainerSubtractionSolid());
00129     }
00130   return CommonFinalConstructor(name,length,outerDiameter,outerMaterial,BDSMagnetColours::Instance()->GetMagnetColour("sectorbend"));
00131   */
00132 }
00133 
00134 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateRectangularBend(G4String      name,
00135                                                                             G4double      length,
00136                                                                             BDSBeamPipe*  beamPipe,
00137                                                                             G4double      outerDiameter,
00138                                                                             G4double      angle,
00139                                                                             G4Material*   outerMaterial)
00140 {
00141 #ifdef BDSDEBUG
00142   G4cout << __METHOD_NAME__ << G4endl;
00143 #endif
00144   CleanUp(); // doesn't use CommonConstructor so must do this manually
00145   
00146   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateRectangularBend(name,length,beamPipe,outerDiameter,
00147                                                                              angle,outerMaterial);
00148   /*
00149   //rectangular bends currently just make a shorter straight volume, so ignore angle for now
00150   CreateCylindricalSolids(name, length, beamPipe, outerDiameter);
00151   return CommonFinalConstructor(name, length, outerDiameter, outerMaterial, BDSMagnetColours::Instance()->GetMagnetColour("rectangularbend"));
00152   */
00153 }
00154 
00155 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateQuadrupole(G4String      name,
00156                                                                        G4double      length,
00157                                                                        BDSBeamPipe*  beamPipe,
00158                                                                        G4double      outerDiameter,
00159                                                                        G4Material*   outerMaterial)
00160 {
00161 #ifdef BDSDEBUG
00162   G4cout << __METHOD_NAME__ << G4endl;
00163 #endif
00164   return CommonConstructor(name, length, beamPipe, 2, outerDiameter, outerMaterial);
00165 }
00166 
00167 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateSextupole(G4String      name,
00168                                                                       G4double      length,
00169                                                                       BDSBeamPipe*  beamPipe,
00170                                                                       G4double      outerDiameter,
00171                                                                       G4Material*   outerMaterial)
00172 {
00173 #ifdef BDSDEBUG
00174   G4cout << __METHOD_NAME__ << G4endl;
00175 #endif
00176   return CommonConstructor(name, length, beamPipe, 3, outerDiameter, outerMaterial);
00177 }
00178 
00179 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateOctupole(G4String      name,
00180                                                                      G4double      length,
00181                                                                      BDSBeamPipe*  beamPipe,
00182                                                                      G4double      outerDiameter,
00183                                                                      G4Material*   outerMaterial)
00184 {
00185 #ifdef BDSDEBUG
00186   G4cout << __METHOD_NAME__ << G4endl;
00187 #endif
00188   return CommonConstructor(name, length, beamPipe, 4, outerDiameter, outerMaterial);
00189 }
00190 
00191 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateDecapole(G4String      name,
00192                                                                      G4double      length,
00193                                                                      BDSBeamPipe*  beamPipe,
00194                                                                      G4double      outerDiameter,
00195                                                                      G4Material*   outerMaterial)
00196 {
00197 #ifdef BDSDEBUG
00198   G4cout << __METHOD_NAME__ << G4endl;
00199 #endif
00200   return CommonConstructor(name, length, beamPipe, 5, outerDiameter, outerMaterial);
00201 }
00202 
00203 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateSolenoid(G4String      name,
00204                                                                      G4double      length,
00205                                                                      BDSBeamPipe*  beamPipe,
00206                                                                      G4double      outerDiameter,
00207                                                                      G4Material*   outerMaterial)
00208 {
00209 #ifdef BDSDEBUG
00210   G4cout << __METHOD_NAME__ << G4endl;
00211 #endif
00212   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateSolenoid(name,length,beamPipe,outerDiameter,outerMaterial);
00213 }
00214 
00215 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateMultipole(G4String      name,
00216                                                                       G4double      length,
00217                                                                       BDSBeamPipe*  beamPipe,
00218                                                                       G4double      outerDiameter,
00219                                                                       G4Material*   outerMaterial)
00220 {
00221 #ifdef BDSDEBUG
00222   G4cout << __METHOD_NAME__ << G4endl;
00223 #endif
00224   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateMultipole(name,length,beamPipe,outerDiameter,outerMaterial);
00225 }
00226 
00227 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateRfCavity(G4String      name,
00228                                                                      G4double      length,
00229                                                                      BDSBeamPipe*  beamPipe,
00230                                                                      G4double      outerDiameter,
00231                                                                      G4Material*   outerMaterial)
00232 {
00233 #ifdef BDSDEBUG
00234   G4cout << __METHOD_NAME__ << G4endl;
00235 #endif
00236   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateRfCavity(name,length,beamPipe,outerDiameter,outerMaterial);
00237 }
00238 
00239 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateMuSpoiler(G4String      name,
00240                                                                       G4double      length,
00241                                                                       BDSBeamPipe*  beamPipe,
00242                                                                       G4double      outerDiameter,
00243                                                                       G4Material*   outerMaterial)
00244 {
00245 #ifdef BDSDEBUG
00246   G4cout << __METHOD_NAME__ << G4endl;
00247 #endif
00248   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateMuSpoiler(name,length,beamPipe,outerDiameter,outerMaterial);
00249 }
00250 
00251 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CreateKicker(G4String      name,
00252                                                                    G4double      length,
00253                                                                    BDSBeamPipe*  beamPipe,
00254                                                                    G4double      outerDiameter,
00255                                                                    G4bool        vertical,
00256                                                                    G4Material*   outerMaterial)
00257 {
00258 #ifdef BDSDEBUG
00259   G4cout << __METHOD_NAME__ << G4endl;
00260 #endif
00261   return BDSMagnetOuterFactoryCylindrical::Instance()->CreateKicker(name,length,beamPipe,outerDiameter,
00262                                                                     vertical,outerMaterial);
00263 }
00264 
00266 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::CommonConstructor(G4String     name,
00267                                                                         G4double     length,
00268                                                                         BDSBeamPipe* beamPipe,
00269                                                                         G4int        order,
00270                                                                         G4double     outerDiameter,
00271                                                                         G4Material*  outerMaterial)
00272 {
00273 #ifdef BDSDEBUG
00274   G4cout << __METHOD_NAME__ << G4endl;
00275 #endif
00276   // reset all pointers and variables to protect against bugs using previous use
00277   CleanUp();
00278   
00279   CalculatePoleAndYoke(outerDiameter, beamPipe, order);
00280   CreatePoleSolid(name, length, order);
00281   CreateYokeAndContainerSolid(name, length, order);
00282   CreateLogicalVolumes(name, length, order, outerMaterial);
00283   PlaceComponents(name, order);
00284   
00285   // record extents
00286   // container radius is just outerDiamter as yoke is circular
00287   G4double containerRadius = outerDiameter + lengthSafety;
00288   std::pair<double,double> extX = std::make_pair(-containerRadius,containerRadius);
00289   std::pair<double,double> extY = std::make_pair(-containerRadius,containerRadius);
00290   std::pair<double,double> extZ = std::make_pair(-length*0.5,length*0.5);
00291   
00292   // build the BDSGeometryComponent instance and return it
00293   BDSGeometryComponent* outer = new BDSGeometryComponent(containerSolid,
00294                                                          containerLV,
00295                                                          extX, extY, extZ);
00296   // REGISTER all lvs - using geometry component base class method
00297   // test if poleLV exists first as some derived classes use their own vector of
00298   // poles and don't use this one - therefore it'll be null
00299   if (poleLV) {
00300     outer->RegisterLogicalVolume(poleLV); }
00301   outer->RegisterLogicalVolume(yokeLV);
00302 
00303   // set sensitive volumes
00304   // test if poleLV exists first as some derived classes use their own vector of
00305   // poles and don't use this one - therefore it'll be null
00306   if (poleLV) {
00307     outer->RegisterSensitiveVolume(poleLV); }
00308   outer->RegisterSensitiveVolume(yokeLV);
00309   
00310   return outer;
00311 }
00312 
00313 void BDSMagnetOuterFactoryPolesBase::CalculatePoleAndYoke(G4double     outerDiameter,
00314                                                           BDSBeamPipe* beamPipe,
00315                                                           G4double     /*order*/)
00316 {
00317   G4double bpRadius = beamPipe->GetContainerRadius();
00318   // check parameters are valid
00319   if (outerDiameter*0.5 < bpRadius)
00320     {
00321       G4cerr << "outerDiameter (" << outerDiameter << ") must be greater than 2*beampipe radius ("
00322              << 2*bpRadius << ")" << G4endl;
00323       exit(1);
00324     }
00325 
00326   // layout markers for the pole and yoke - radially out from centre
00327   poleStartRadius       = bpRadius + lengthSafety;
00328   yokeFinishRadius      = outerDiameter*0.5;
00329   G4double totalLength  = yokeFinishRadius - poleStartRadius;
00330   poleFinishRadius      = poleStartRadius + poleFraction*totalLength;
00331   yokeStartRadius       = poleFinishRadius + lengthSafety;
00332 }
00333 
00334 void BDSMagnetOuterFactoryPolesBase::CreatePoleSolid(G4String     name,
00335                                                      G4double     length,
00336                                                      G4int        order)
00337 {
00338   G4int nPoles = 2*order;
00339   
00340   // full circle is divided into segments for each pole
00341   G4double segmentAngleWidth = CLHEP::twopi / (G4double)nPoles;
00342   G4double poleAngle = segmentAngleWidth * poleAngularFraction;
00343 
00344   // compose pole of an annulus of a certain angle plus
00345   // an ellipsoid at the inner side. make the union of the
00346   // two to give a typical pole shape - curved inner surface
00347   // with increasing width outwards
00348   
00349   // make some % of pole length curved ellipsoidal surface
00350   G4double poleLength          = poleFinishRadius - poleStartRadius - 2*lengthSafety;
00351   G4double ellipsoidHeight     = poleTipFraction*poleLength;
00352   //G4double annulusHeight       = poleLength - ellipsoidHeight;
00353   G4double ellipsoidCentre     = poleStartRadius + ellipsoidHeight*0.5;
00354 
00355   // work out the chord length
00356   G4double ellipsoidWidth      = 2*(poleStartRadius + 0.5*ellipsoidHeight) * tan(poleAngle*0.5);
00357   
00358   G4double annulusStartRadius  = ellipsoidCentre / cos(poleAngle*0.5); //so edges line up with ellipsoid edges
00359   G4double annulusFinishRadius = poleFinishRadius;
00360   
00361   G4VSolid* poleTip = new G4EllipticalTube(name + "_pole_tip_solid",   // name
00362                                            ellipsoidHeight*0.5,        // x half width
00363                                            ellipsoidWidth*0.5,         // y half width
00364                                            length*0.5 - lengthSafety); // z half width
00365 
00366   G4VSolid* poleAnnulus = new G4Tubs(name + "_pole_annulus_solid", // name
00367                                      annulusStartRadius,           // start radius
00368                                      annulusFinishRadius,          // finish radius
00369                                      length*0.5 - lengthSafety,    // z half length
00370                                      -poleAngle*0.5,               // start angle
00371                                      poleAngle);                   // sweep angle
00372 
00373   // note annulus is defined from centre of rotation
00374   G4ThreeVector ellipsoidTranslation(poleStartRadius + ellipsoidHeight*0.5, 0, 0);
00375   // the centre of the union solid will be that of the 1st solid - the annulus - ie 0,0,0
00376   poleSolid = new G4UnionSolid(name + "_pole_solid", // name
00377                                poleAnnulus,          // solid 1
00378                                poleTip,              // solid 2
00379                                0,                    // rotation matrix
00380                                ellipsoidTranslation);// translation of poleTip
00381 }
00382 
00383 void BDSMagnetOuterFactoryPolesBase::CreateYokeAndContainerSolid(G4String      name,
00384                                                                  G4double      length,
00385                                                                  G4int         /*order*/)
00386 {
00387   // circular yoke so pretty easy
00388   yokeSolid = new G4Tubs(name + "_yoke_solid",      // name
00389                          yokeStartRadius,           // start radius
00390                          yokeFinishRadius,          // finish radius
00391                          length*0.5 - lengthSafety, // z half length
00392                          0,                         // start angle
00393                          CLHEP::twopi);             // sweep angle
00394 
00395   // note container must have hole in it for the beampipe to fit in!
00396   // poled geometry doesn't fit tightly to beampipe so can alays use a circular aperture
00397   containerSolid = new G4Tubs(name + "_container_solid",       // name
00398                               poleStartRadius,                 // start radius
00399                               yokeFinishRadius + lengthSafety, // finish radius
00400                               length*0.5,                      // z half length
00401                               0,                               // start angle
00402                               CLHEP::twopi);                   // sweep angle
00403 }
00404 
00405 void BDSMagnetOuterFactoryPolesBase::TestInputParameters(BDSBeamPipe* beamPipe,
00406                                                          G4double&    outerDiameter,
00407                                                          G4Material*& outerMaterial)// reference to a pointer
00408 {
00409   //function arguments by reference to they can be modified in place
00410   //check outer material is something
00411   if (!outerMaterial)
00412     {outerMaterial = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->GetEmptyMaterial());}
00413 
00414   // ensure box size is bigger than the beampipe
00415   if (beamPipe->ContainerIsCircular()) {
00416     // if it's circular, just check radius
00417     if (outerDiameter < 2*(beamPipe->GetContainerRadius()) )
00418       {outerDiameter = 2*(beamPipe->GetContainerRadius()) + 1*CLHEP::mm;}
00419   } else {
00420     // it's not circular - have a look at extents
00421     // +ve - -ve
00422     G4double extentX = beamPipe->GetExtentX().second - beamPipe->GetExtentX().first;
00423     G4double extentY = beamPipe->GetExtentY().second - beamPipe->GetExtentY().first;
00424     if ( (outerDiameter < extentX) || (outerDiameter < extentY) ) {
00425       // outerDiameter isn't sufficient for range in x or y
00426       outerDiameter = std::max(extentX,extentY) + 1*CLHEP::mm;
00427     }
00428   }
00429 }
00430 
00431 void BDSMagnetOuterFactoryPolesBase::CreateLogicalVolumes(G4String   name,
00432                                                           G4double   length,
00433                                                           G4int      order,
00434                                                           G4Material* outerMaterial)
00435 {  
00436   // build the logical volumes
00437   poleLV   = new G4LogicalVolume(poleSolid,
00438                                  outerMaterial,
00439                                  name + "_pole_lv");
00440 
00441   yokeLV   = new G4LogicalVolume(yokeSolid,
00442                                  outerMaterial,
00443                                  name + "_yoke_lv");
00444 
00445   G4Material* emptyMaterial = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->GetEmptyMaterial());
00446   containerLV = new G4LogicalVolume(containerSolid,
00447                                     emptyMaterial,
00448                                     name + "_container_lv");
00449   
00450   // VISUAL ATTRIBUTES
00451   // set visual attributes
00452   G4Colour* magnetColour = BDSMagnetColours::Instance()->GetMagnetColour(order);
00453   G4VisAttributes* outerVisAttr = new G4VisAttributes(*magnetColour);
00454   outerVisAttr->SetVisibility(true);
00455   outerVisAttr->SetForceLineSegmentsPerCircle(nSegmentsPerCircle);
00456   poleLV->SetVisAttributes(outerVisAttr);
00457   yokeLV->SetVisAttributes(outerVisAttr);
00458   // container
00459   if (BDSExecOptions::Instance()->GetVisDebug())
00460     {containerLV->SetVisAttributes(BDSGlobalConstants::Instance()->GetVisibleDebugVisAttr());}
00461   else
00462     {containerLV->SetVisAttributes(BDSGlobalConstants::Instance()->GetInvisibleVisAttr());}
00463 
00464   // USER LIMITS
00465   // set user limits based on bdsim user specified parameters
00466 #ifndef NOUSERLIMITS
00467   G4UserLimits* outerUserLimits = new G4UserLimits("outer_cuts");
00468   outerUserLimits->SetMaxAllowedStep( length * maxStepFactor );
00469   outerUserLimits->SetUserMinEkine(BDSGlobalConstants::Instance()->GetThresholdCutCharged());
00470   outerUserLimits->SetUserMaxTime(BDSGlobalConstants::Instance()->GetMaxTime());
00471   //attach cuts to volumes
00472   poleLV->SetUserLimits(outerUserLimits);
00473   yokeLV->SetUserLimits(outerUserLimits);
00474   containerLV->SetUserLimits(outerUserLimits);
00475 #endif
00476 }
00477 
00478 void BDSMagnetOuterFactoryPolesBase::PlaceComponents(G4String name,
00479                                                      G4int    order)
00480 {
00481   // PLACEMENT
00482   // place the components inside the container
00483   // note we don't need the pointer for placements - it's registered upon construction with g4
00484   new G4PVPlacement((G4RotationMatrix*)0,         // no rotation
00485                     (G4ThreeVector)0,             // position
00486                     yokeLV,                       // lv to be placed
00487                     name + "_yoke_pv",            // name
00488                     containerLV,                  // mother lv to be placed in
00489                     false,                        // no boolean operation
00490                     0,                            // copy number
00491                     checkOverlaps);               // whether to check overlaps
00492   
00493   // pole placement
00494   for (G4int n = 0; n < 2*order; ++n)
00495     {
00496       // prepare a new rotation matrix - must be new and can't reuse the same one
00497       // as the placement doesn't own it - changing the existing one will affect all
00498       // previously placed objects
00499       G4RotationMatrix* rm  = new G4RotationMatrix();
00500       G4double segmentAngle = CLHEP::twopi/(G4double)(2*order); // angle per pole
00501       rm->rotateZ((n+0.5)*segmentAngle + CLHEP::pi*0.5);
00502 
00503       new G4PVPlacement(rm,                 // rotation
00504                         (G4ThreeVector)0,   // position
00505                         poleLV,             // logical volume
00506                         name + "_pv",       // name      
00507                         containerLV,        // mother lv to be placed in
00508                         false,              // no boolean operation
00509                         n,                  // copy number
00510                         checkOverlaps);     // check overlaps
00511       //name + "_pole_" + printf("_%d_pv", n), // name
00512     }
00513 }
00514 
00515 BDSGeometryComponent* BDSMagnetOuterFactoryPolesBase::KickerConstructor(G4String     name,
00516                                                                         G4double     length,
00517                                                                         G4double     angle,
00518                                                                         BDSBeamPipe* beamPipe,
00519                                                                         G4double     outerDiameter,
00520                                                                         G4Material*  outerMaterial,
00521                                                                         G4bool       isVertical)
00522 {
00523   // test input parameters
00524   
00525   // geometrical design parameters
00526   G4double yokeWidthFraction    = 0.2; // the fraction of the full width that the yoke thickness is
00527   G4double coilWidthFraction    = 0.3; // the fraction of the full width that the coil full width is
00528   G4double coilHeightFraction   = 0.4; // the fraction of the full height that the coil full height is
00529 
00530   // calculate geometrical parameters
00531   G4double beamPipeContainerRadius = beamPipe->GetContainerRadius(); 
00532 
00533   G4double coilHalfWidth        = coilWidthFraction  * outerDiameter * 0.5;
00534   G4double coilHalfHeight       = coilHeightFraction * outerDiameter * 0.5;
00535   
00536   G4double containerHalfWidth   = outerDiameter * 0.5;
00537   G4double containerHalfHeight  = outerDiameter * 0.5;
00538   
00539   G4double yokeHalfWidth        = containerHalfWidth  - coilHalfWidth  - lengthSafety; // - lengthSafety to fit inside container
00540   G4double yokeHalfHeight       = containerHalfHeight - lengthSafety;
00541   
00542   G4double yokeCutOutHalfWidth  = yokeHalfWidth  * (1 - yokeWidthFraction);
00543   G4double yokeCutOutHalfHeight = yokeHalfHeight * (1 - yokeWidthFraction);
00544 
00545   G4double poleHalfWidth        = beamPipeContainerRadius;
00546   G4double poleHalfHeight       = 0.5 * (yokeCutOutHalfHeight - beamPipeContainerRadius);
00547   
00548   // calculate offsets and placement vectors
00549   G4int massOffset = 1;
00550   if (angle > 0)
00551     {massOffset = -1;}
00552   G4ThreeVector containerTranslation = G4ThreeVector((containerHalfWidth - beamPipeContainerRadius), 0, 0);
00553   G4ThreeVector yokeTranslation      = G4ThreeVector(yokeHalfWidth - beamPipeContainerRadius, 0, 0);
00554   G4ThreeVector upperPoleTranslation = G4ThreeVector(0, beamPipeContainerRadius + poleHalfHeight,    0);
00555   G4ThreeVector lowerPoleTranslation = G4ThreeVector(0, -(beamPipeContainerRadius + poleHalfHeight), 0);
00556   G4ThreeVector outerCoilTranslation = G4ThreeVector(yokeHalfWidth + coilHalfWidth, 0, 0);
00557   G4double      innerCoilXOffset     = yokeHalfWidth - ( (yokeHalfWidth - yokeCutOutHalfWidth)*2.) - coilHalfWidth;
00558   G4ThreeVector innerCoilTranslation = G4ThreeVector(innerCoilXOffset, 0, 0);
00559 
00560   // build container
00561   G4VSolid* container  = new G4Box(name + "_container_solid",           // name
00562                                    containerHalfWidth,                  // x half width
00563                                    containerHalfHeight,                 // y half width
00564                                    length*0.5);                         // z half length
00565   
00566   // build yoke & pole piece
00567   G4VSolid* yokeBox    = new G4Box(name + "_yoke_box_solid",            // name
00568                                    yokeHalfWidth,                       // x half width
00569                                    yokeHalfHeight,                      // y half width
00570                                    length*0.5 - lengthSafety);          // z half width
00571 
00572   G4VSolid* yokeCutOut = new G4Box(name + "_yoke_cut_out_solid",        // name
00573                                    yokeCutOutHalfWidth,                 // x half width
00574                                    yokeCutOutHalfHeight,                // y half width
00575                                    length);                             // z half width (long for unambiguous subtraction)
00576 
00577   G4double      yokeSubtractionXOffset = yokeHalfWidth * yokeWidthFraction * massOffset;
00578   G4ThreeVector yokeSubtractionOffset  = G4ThreeVector(yokeSubtractionXOffset,0,0);
00579   G4VSolid* yoke       = new G4SubtractionSolid(name + "_yoke_solid",   // name
00580                                                 yokeBox,                // solid 1
00581                                                 yokeCutOut,             // minus solid 2
00582                                                 0,                      // rotation
00583                                                 yokeSubtractionOffset); // translation
00584   
00585   G4VSolid* pole       = new G4Box(name + "_pole_solid",                // name
00586                                    poleHalfWidth,                       // x half width
00587                                    poleHalfHeight,                      // y half width
00588                                    length*0.5 - lengthSafety);          // z half width
00589   
00590   // build coils
00591   G4VSolid* coil       = new G4Box(name + "_coil_solid",                // name
00592                                    coilHalfWidth,                       // x half width
00593                                    coilHalfHeight,                      // y half width
00594                                    length*0.5 - lengthSafety);          // z half width
00595 
00596   // logical volumes
00597   G4Material* copper = BDSMaterials::Instance()->GetMaterial("copper");
00598   G4Material* empty  = BDSMaterials::Instance()->GetMaterial(BDSGlobalConstants::Instance()->GetEmptyMaterial());
00599   G4LogicalVolume* containerLV = new G4LogicalVolume(container,               // solid
00600                                                      empty,                   // material
00601                                                      name + "_container_lv"); // name
00602   G4LogicalVolume* yokeLV      = new G4LogicalVolume(yoke,                    // solid
00603                                                      outerMaterial,           // material
00604                                                      name + "_yoke_lv");      // name
00605   G4LogicalVolume* poleLV      = new G4LogicalVolume(pole,                    // solid
00606                                                      outerMaterial,           // material
00607                                                      name + "_pole_lv");      // name
00608   G4LogicalVolume* coilLV      = new G4LogicalVolume(coil,                    // solid
00609                                                      copper,                  // material
00610                                                      name + "_coil_lv");      // name
00611 
00612   // VISUAL ATTRIBUTES
00613   // set visual attributes
00614   std::string magnetType;
00615   if (isVertical)
00616     {magnetType = "vkicker";}
00617   else
00618     {magnetType = "hkicker";}
00619 
00620   // yoke and pole
00621   G4Colour* magnetColour = BDSMagnetColours::Instance()->GetMagnetColour(magnetType);
00622   G4VisAttributes* outerVisAttr = new G4VisAttributes(*magnetColour);
00623   outerVisAttr->SetVisibility(true);
00624   // no curved surfaces so don't need to set nsegments
00625   yokeLV->SetVisAttributes(outerVisAttr);
00626   poleLV->SetVisAttributes(outerVisAttr);
00627 
00628   // coil
00629   G4Colour* coilColour  = BDSMagnetColours::Instance()->GetMagnetColour("coil");
00630   G4VisAttributes* coilVisAttr = new G4VisAttributes(*coilColour);
00631   coilVisAttr->SetVisibility(true);
00632   coilLV->SetVisAttributes(coilVisAttr);
00633 
00634   // container
00635   if (BDSExecOptions::Instance()->GetVisDebug())
00636     {containerLV->SetVisAttributes(BDSGlobalConstants::Instance()->GetVisibleDebugVisAttr());}
00637   else
00638     {containerLV->SetVisAttributes(BDSGlobalConstants::Instance()->GetInvisibleVisAttr());}
00639 
00640   // user limits
00641 #ifndef NOUSERLIMITS
00642   G4UserLimits* outerUserLimits = new G4UserLimits("outer_cuts");
00643   outerUserLimits->SetMaxAllowedStep( length * maxStepFactor );
00644   outerUserLimits->SetUserMinEkine(BDSGlobalConstants::Instance()->GetThresholdCutCharged());
00645   outerUserLimits->SetUserMaxTime(BDSGlobalConstants::Instance()->GetMaxTime());
00646   // attach cuts to volumes
00647   yokeLV->SetUserLimits(outerUserLimits);
00648   poleLV->SetUserLimits(outerUserLimits);
00649   coilLV->SetUserLimits(outerUserLimits);
00650   containerLV->SetUserLimits(outerUserLimits);
00651 #endif
00652 
00653   // place components
00654   new G4PVPlacement((G4RotationMatrix*)0,         // no rotation
00655                     yokeTranslation,              // position
00656                     yokeLV,                       // lv to be placed
00657                     name + "_yoke_pv",            // name
00658                     containerLV,                  // mother lv to be place in
00659                     false,                        // no boolean operation
00660                     0,                            // copy number
00661                     checkOverlaps);
00662 
00663   new G4PVPlacement((G4RotationMatrix*)0,         // no rotation
00664                     lowerPoleTranslation,         // position
00665                     poleLV,                       // lv to be placed
00666                     name + "_lower_pole_pv",      // name
00667                     containerLV,                  // mother lv to be place in
00668                     false,                        // no boolean operation
00669                     0,                            // copy number
00670                     checkOverlaps);
00671 
00672   new G4PVPlacement((G4RotationMatrix*)0,         // no rotation
00673                     upperPoleTranslation,         // position
00674                     poleLV,                       // lv to be placed
00675                     name + "_upper_pole_pv",      // name
00676                     containerLV,                  // mother lv to be place in
00677                     false,                        // no boolean operation
00678                     0,                            // copy number
00679                     checkOverlaps);
00680 
00681   new G4PVPlacement((G4RotationMatrix*)0,         // no rotation
00682                     outerCoilTranslation,         // position
00683                     coilLV,                       // lv to be placed
00684                     name + "_outer_coil_pv",      // name
00685                     containerLV,                  // mother lv to be place in
00686                     false,                        // no boolean operation
00687                     0,                            // copy number
00688                     checkOverlaps);
00689 
00690   new G4PVPlacement((G4RotationMatrix*)0,         // no rotation
00691                     innerCoilTranslation,         // position
00692                     coilLV,                       // lv to be placed
00693                     name + "_inner_coil_pv",      // name
00694                     containerLV,                  // mother lv to be place in
00695                     false,                        // no boolean operation
00696                     0,                            // copy number
00697                     checkOverlaps);
00698 
00699   // record extents
00700   // container radius is just outerDiamter as yoke is circular
00701   G4double containerRadius = 0.5*outerDiameter;
00702   G4double extXPos = outerDiameter - beamPipeContainerRadius;
00703   G4double extXNeg = -beamPipeContainerRadius;
00704   std::pair<double,double> extX = std::make_pair(extXNeg,extXPos);
00705   std::pair<double,double> extY = std::make_pair(-containerRadius,containerRadius);
00706   std::pair<double,double> extZ = std::make_pair(-length*0.5,length*0.5);
00707   
00708   // construct geometry component
00709   BDSGeometryComponent* kicker = new BDSGeometryComponent(container,
00710                                                           containerLV,
00711                                                           extX, extY, extZ,
00712                                                           containerTranslation);
00713 
00714   // register logical volumes
00715   kicker->RegisterLogicalVolume(yokeLV);
00716   kicker->RegisterLogicalVolume(poleLV);
00717   kicker->RegisterLogicalVolume(coilLV);
00718 
00719   // register sensitive volumes
00720   kicker->RegisterSensitiveVolume(yokeLV);
00721   kicker->RegisterSensitiveVolume(poleLV);
00722   kicker->RegisterSensitiveVolume(coilLV);
00723   
00724   return kicker;
00725 }

Generated on 28 Jun 2015 for BDSIM by  doxygen 1.4.7