BDSIM
BDSIM is a Geant4 extension toolkit for simulation of particle transport in accelerator beamlines.
Loading...
Searching...
No Matches
BDSFieldFactory.cc
1/*
2Beam Delivery Simulation (BDSIM) Copyright (C) Royal Holloway,
3University of London 2001 - 2023.
4
5This file is part of BDSIM.
6
7BDSIM is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published
9by the Free Software Foundation version 3 of the License.
10
11BDSIM is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with BDSIM. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "BDSArrayReflectionType.hh"
20#include "BDSBeamPipeInfo.hh"
21#include "BDSDebug.hh"
22#include "BDSException.hh"
23#include "BDSPTCOneTurnMap.hh"
24#include "BDSPrimaryGeneratorAction.hh"
25#include "BDSFieldClassType.hh"
26#include "BDSFieldE.hh"
27#include "BDSFieldEGlobal.hh"
28#include "BDSFieldEGlobalPlacement.hh"
29#include "BDSFieldEInterpolated.hh"
30#include "BDSFieldEInterpolated2Layer.hh"
31#include "BDSFieldESinusoid.hh"
32#include "BDSFieldEZero.hh"
33#include "BDSFieldEM.hh"
34#include "BDSFieldEMGlobal.hh"
35#include "BDSFieldEMGlobalPlacement.hh"
36#include "BDSFieldEMInterpolated.hh"
37#include "BDSFieldEMRFCavity.hh"
38#include "BDSFieldEMZero.hh"
39#include "BDSFieldFactory.hh"
40#include "BDSFieldInfo.hh"
41#include "BDSFieldLoader.hh"
42#include "BDSFieldMag.hh"
43#include "BDSFieldMagDecapole.hh"
44#include "BDSFieldMagDipole.hh"
45#include "BDSFieldMagDipoleOuter.hh"
46#include "BDSFieldMagDipoleOuterOld.hh"
47#include "BDSFieldMagDipoleQuadrupole.hh"
48#include "BDSFieldMagGlobal.hh"
49#include "BDSFieldMagGlobalPlacement.hh"
50#include "BDSFieldMagInterpolated.hh"
51#include "BDSFieldMagInterpolated2Layer.hh"
52#include "BDSFieldMagMultipole.hh"
53#include "BDSFieldMagMultipoleOuter.hh"
54#include "BDSFieldMagMultipoleOuterDual.hh"
55#include "BDSFieldMagMultipoleOuterDualOld.hh"
56#include "BDSFieldMagMultipoleOuterOld.hh"
57#include "BDSFieldMagMuonSpoiler.hh"
58#include "BDSFieldMagOctupole.hh"
59#include "BDSFieldMagQuadrupole.hh"
60#include "BDSFieldMagSextupole.hh"
61#include "BDSFieldMagSolenoidSheet.hh"
62#include "BDSFieldMagSkewOwn.hh"
63#include "BDSFieldMagUndulator.hh"
64#include "BDSFieldMagZero.hh"
65#include "BDSFieldObjects.hh"
66#include "BDSFieldType.hh"
67#include "BDSGlobalConstants.hh"
68#include "BDSIntegratorCavityFringe.hh"
69#include "BDSIntegratorDecapole.hh"
70#include "BDSIntegratorDipoleRodrigues.hh"
71#include "BDSIntegratorDipoleRodrigues2.hh"
72#include "BDSIntegratorDipoleFringe.hh"
73#include "BDSIntegratorDipoleFringeScaling.hh"
74#include "BDSIntegratorDipoleQuadrupole.hh"
75#include "BDSIntegratorEuler.hh"
76#include "BDSIntegratorG4RK4MinStep.hh"
77#include "BDSIntegratorKickerThin.hh"
78#include "BDSIntegratorOctupole.hh"
79#include "BDSIntegratorQuadrupole.hh"
80#include "BDSIntegratorMultipoleThin.hh"
81#include "BDSIntegratorParallelTransport.hh"
82#include "BDSIntegratorSextupole.hh"
83#include "BDSIntegratorSolenoid.hh"
84#include "BDSIntegratorTeleporter.hh"
85#include "BDSIntegratorRMatrixThin.hh"
86#include "BDSIntegratorType.hh"
87#include "BDSMagnetOuterFactoryLHC.hh"
88#include "BDSMagnetStrength.hh"
89#include "BDSMagnetType.hh"
90#include "BDSModulator.hh"
91#include "BDSModulatorInfo.hh"
92#include "BDSModulatorSinT.hh"
93#include "BDSModulatorTopHatT.hh"
94#include "BDSModulatorType.hh"
95#include "BDSParser.hh"
96#include "BDSParticleDefinition.hh"
97#include "BDSUtilities.hh"
98#include "BDSWarning.hh"
99
100#include "parser/field.h"
101#include "parser/modulator.h"
102
103#include "globals.hh" // geant4 types / globals
104#include "G4EquationOfMotion.hh"
105#include "G4EqMagElectricField.hh"
106#include "G4MagIntegratorStepper.hh"
107#include "G4Mag_UsualEqRhs.hh"
108#include "G4RotationMatrix.hh"
109#include "G4String.hh"
110#include "G4ThreeVector.hh"
111#include "G4Transform3D.hh"
112#include "G4Version.hh"
113
114// geant4 integrators
115#include "G4CashKarpRKF45.hh"
116#include "G4ClassicalRK4.hh"
117#include "G4ConstRK4.hh"
118#include "G4ExactHelixStepper.hh"
119#include "G4ExplicitEuler.hh"
120#include "G4HelixExplicitEuler.hh"
121#include "G4HelixHeum.hh"
122#include "G4HelixImplicitEuler.hh"
123#include "G4HelixMixedStepper.hh"
124#include "G4HelixSimpleRunge.hh"
125#include "G4ImplicitEuler.hh"
126#include "G4NystromRK4.hh"
127#include "G4RKG3_Stepper.hh"
128#include "G4SimpleHeum.hh"
129#include "G4SimpleRunge.hh"
130#if G4VERSION_NUMBER > 1029
131#include "G4BogackiShampine23.hh"
132#include "G4BogackiShampine45.hh"
133#include "G4DoLoMcPriRK34.hh"
134#include "G4DormandPrince745.hh"
135#include "G4DormandPrinceRK56.hh"
136#include "G4TsitourasRK45.hh"
137#endif
138#if G4VERSION_NUMBER > 1039
139#include "G4DormandPrinceRK78.hh"
140#include "G4RK547FEq1.hh"
141#include "G4RK547FEq2.hh"
142#include "G4RK547FEq3.hh"
143#endif
144
145#include "CLHEP/Units/SystemOfUnits.h"
146#include "CLHEP/Vector/EulerAngles.h"
147
148#include <limits>
149#include <map>
150#include <utility>
151#include <vector>
152
155
157
159{
160 if (!instance)
161 {instance = new BDSFieldFactory();}
162 return instance;
163}
164
166 useOldMultipoleOuterFields(false)
167{
168 G4double defaultRigidity = std::numeric_limits<double>::max();
169 if (designParticle)
170 {defaultRigidity = designParticle->BRho();}
171 // we do this so we don't have to have used the parser to use this class
173 {
175 PrepareFieldDefinitions(BDSParser::Instance()->GetFields(), defaultRigidity);
176 }
177 useOldMultipoleOuterFields = BDSGlobalConstants::Instance()->UseOldMultipoleOuterFields();
178}
179
180BDSFieldFactory::~BDSFieldFactory()
181{
182 for (auto& info : parserDefinitions)
183 {delete info.second;}
184 for (auto& info : parserModulatorDefinitions)
185 {delete info.second;}
186}
187
188void BDSFieldFactory::PrepareFieldDefinitions(const std::vector<GMAD::Field>& definitions,
189 G4double defaultBRho)
190{
191 for (const auto& definition : definitions)
192 {
193 if (definition.type.empty())
194 {
195 G4String msg = "\"type\" not specified in field definition \"";
196 msg += definition.name + "\", but required.";
197 throw BDSException(__METHOD_NAME__, msg);
198 }
199 BDSFieldType fieldType = BDS::DetermineFieldType(definition.type);
200 BDSIntegratorType intType = BDS::DetermineIntegratorType(definition.integrator);
201
202 G4ThreeVector offset = G4ThreeVector(definition.x*CLHEP::m,
203 definition.y*CLHEP::m,
204 definition.z*CLHEP::m);
205
206 G4RotationMatrix rm;
207 if (definition.axisAngle)
208 {
209 G4ThreeVector axis = G4ThreeVector(definition.axisX,
210 definition.axisY,
211 definition.axisZ);
212 rm = G4RotationMatrix(axis, definition.angle*CLHEP::rad);
213 }
214 else
215 {
216 if (BDS::IsFinite(definition.phi) ||
217 BDS::IsFinite(definition.theta) ||
218 BDS::IsFinite(definition.psi))
219 {// only build if finite
220 CLHEP::HepEulerAngles ang = CLHEP::HepEulerAngles(definition.phi*CLHEP::rad,
221 definition.theta*CLHEP::rad,
222 definition.psi*CLHEP::rad);
223 rm = G4RotationMatrix(ang);
224 }
225 // else rm is default rotation matrix
226 }
227
228 G4Transform3D transform = G4Transform3D(rm, offset);
229
230 BDSFieldFormat magFormat = BDSFieldFormat::none;
231 G4String magFile = "";
232 G4bool magFileSpecified = !definition.magneticFile.empty();
233 if (magFileSpecified)
234 {
235 std::pair<G4String, G4String> bf = BDS::SplitOnColon(G4String(definition.magneticFile));
236 magFormat = BDS::DetermineFieldFormat(bf.first);
237 magFile = BDS::GetFullPath(bf.second);
238 }
239
240 BDSFieldFormat eleFormat = BDSFieldFormat::none;
241 G4String eleFile = "";
242 G4bool eleFileSpecified = !definition.electricFile.empty();
243 if (eleFileSpecified)
244 {
245 std::pair<G4String, G4String> ef = BDS::SplitOnColon(G4String(definition.electricFile));
246 eleFormat = BDS::DetermineFieldFormat(ef.first);
247 eleFile = BDS::GetFullPath(ef.second);
248 }
249
250 BDSInterpolatorType magIntType = BDSInterpolatorType::cubic3d;
251 if (magFileSpecified)
252 {// determine and check type of integrator
253 G4int nDimFF = BDS::NDimensionsOfFieldFormat(magFormat);
254 if (!definition.magneticInterpolator.empty())
255 {
256 magIntType = BDS::DetermineInterpolatorType(G4String(definition.magneticInterpolator));
257 // detect if an auto type and match up accordingly, else check it's the right one
258 if (BDS::InterpolatorTypeIsAuto(magIntType))
259 {magIntType = BDS::InterpolatorTypeSpecificFromAuto(nDimFF, magIntType);}
260 else
261 {
262 G4int nDimInt = BDS::NDimensionsOfInterpolatorType(magIntType);
263 if (nDimFF != nDimInt)
264 {
265 G4String message = "mismatch in number of dimensions between magnetic interpolator ";
266 message += "and field map format for field definition \"" + definition.name + "\"";
267 throw BDSException(__METHOD_NAME__, message);
268 }
269 }
270 }
271 else
272 {magIntType = DefaultInterpolatorType(nDimFF);}
273 }
274
275 BDSInterpolatorType eleIntType = BDSInterpolatorType::cubic3d;
276 if (eleFileSpecified)
277 {// determine and check type of integrator
278 G4int nDimFF = BDS::NDimensionsOfFieldFormat(eleFormat);
279 if (!definition.electricInterpolator.empty())
280 {
281 eleIntType = BDS::DetermineInterpolatorType(G4String(definition.electricInterpolator));
282 // detect if an auto type and match up accordingly, else check it's the right one
283 if (BDS::InterpolatorTypeIsAuto(eleIntType))
284 {eleIntType = BDS::InterpolatorTypeSpecificFromAuto(nDimFF, eleIntType);}
285 else
286 {
287 G4int nDimInt = BDS::NDimensionsOfInterpolatorType(eleIntType);
288 if (nDimFF != nDimInt)
289 {
290 G4String message = "mismatch in number of dimensions between electric interpolator ";
291 message += "and field map format for field definition \"" + definition.name + "\"";
292 throw BDSException(__METHOD_NAME__, message);
293 }
294 }
295 }
296 else
297 {eleIntType = DefaultInterpolatorType(nDimFF);}
298 }
299
300 G4UserLimits* fieldLimit = nullptr;
301 if (definition.maximumStepLength > 0)
302 {// only assign if specified
303 auto defaultUL = BDSGlobalConstants::Instance()->DefaultUserLimits();
304 // copy the default and update with the length of the object rather than the default 1m
305 G4double limit = G4double(definition.maximumStepLength) * CLHEP::m;
306 G4UserLimits* ul = BDS::CreateUserLimits(defaultUL, limit, 1.0);
307 // only specify a user limit object if the step length was specified
308 if (ul != defaultUL)
309 {fieldLimit = ul;}
310 }
311
313 G4double poleTipRadius = BDSGlobalConstants::Instance()->DefaultBeamPipeModel()->aper1;
314 if (!definition.fieldParameters.empty())
315 {PrepareFieldStrengthFromParameters(st, definition.fieldParameters, poleTipRadius);}
316
317 BDSFieldInfo* info = new BDSFieldInfo(fieldType,
318 defaultBRho,
319 intType,
320 st,
321 G4bool(definition.globalTransform),
322 transform,
323 magFile,
324 magFormat,
325 magIntType,
326 eleFile,
327 eleFormat,
328 eleIntType,
329 false, /*don't cache transforms*/
330 G4double(definition.eScaling),
331 G4double(definition.bScaling),
332 G4double(definition.t*CLHEP::s),
333 G4bool(definition.autoScale),
334 fieldLimit);
335 info->SetScalingRadius(poleTipRadius);
336 info->SetModulatorInfo(GetModulatorDefinition(definition.fieldModulator));
337
338 if (!definition.magneticSubField.empty())
339 {
340 if (definition.magneticSubField == definition.name)
341 {throw BDSException(__METHOD_NAME__, "error in \"" + definition.name + "\": magneticSubField cannot be the field itself");}
342 info->SetMagneticSubField(G4String(definition.magneticSubField));
343 }
344 if (!definition.electricSubField.empty())
345 {
346 if (definition.electricSubField == definition.name)
347 {throw BDSException(__METHOD_NAME__, "error in \"" + definition.name + "\": electricSubField cannot be the field itself");}
348 info->SetElectricSubField(G4String(definition.electricSubField));
349 }
350 if (!definition.magneticReflection.empty())
351 {
352 G4String magneticReflection = G4String(definition.magneticReflection);
353 BDSArrayReflectionTypeSet mar = BDS::DetermineArrayReflectionTypeSet(magneticReflection);
354 info->SetMagneticArrayReflectionType(mar);
355 }
356 if (!definition.electricReflection.empty())
357 {
358 G4String electricReflection = G4String(definition.electricReflection);
359 BDSArrayReflectionTypeSet ear = BDS::DetermineArrayReflectionTypeSet(electricReflection);
360 info->SetElectricArrayReflectionType(ear);
361 }
362
363 info->SetNameOfParserDefinition(G4String(definition.name));
364 if (BDSGlobalConstants::Instance()->Verbose())
365 {
366 G4cout << "Definition: \"" << definition.name << "\"" << G4endl;
367 G4cout << *info << G4endl;
368 }
369 parserDefinitions[G4String(definition.name)] = info;
370 }
371}
372
373void BDSFieldFactory::PrepareModulatorDefinitions(const std::vector<GMAD::Modulator>& definitions)
374{
375 for (const auto& definition : definitions)
376 {
377 if (definition.type.empty())
378 {
379 G4String msg = "\"type\" not specified in modulator definition \"";
380 msg += definition.name + "\", but required.";
381 throw BDSException(__METHOD_NAME__, msg);
382 }
383 BDSModulatorType modulatorType = BDS::DetermineModulatorType(definition.type);
384
385 // We can't calculate any global phase here because this one modulator info may
386 // be used by multiple beam line elements at different locations
387 BDSModulatorInfo* info = new BDSModulatorInfo(modulatorType,
388 definition.frequency * CLHEP::hertz,
389 definition.phase * CLHEP::rad,
390 definition.tOffset * CLHEP::s,
391 definition.amplitudeScale,
392 definition.amplitudeOffset,
393 definition.T0,
394 definition.T1);
395 info->nameOfParserDefinition = definition.name;
396 parserModulatorDefinitions[G4String(definition.name)] = info;
397 }
398}
399
400G4double BDSFieldFactory::CalculateGlobalPhase(G4double oscillatorFrequency,
401 G4double tOffsetIn)
402{
403 if (!BDS::IsFinite(oscillatorFrequency))
404 {return 0;} // prevent division by 0 for period
405 G4double period = 1. / oscillatorFrequency;
406 G4double nPeriods = tOffsetIn / period;
407 // phase is the remainder from total phase / N*2pi, where n is unknown.
408 G4double integerPart = 0;
409 G4double fractionalPart = std::modf(nPeriods, &integerPart);
410 G4double phaseOffset = fractionalPart * CLHEP::twopi;
411 return phaseOffset;
412}
413
414G4double BDSFieldFactory::CalculateGlobalPhase(const BDSModulatorInfo& modulatorInfo,
415 const BDSFieldInfo& fieldInfo)
416{
417 G4double synchronousT0 = 0.0;
418 auto magnetStrength = fieldInfo.MagnetStrength();
419 if (magnetStrength)
420 {synchronousT0 = (*magnetStrength)["synchronousT0"];}
421
422 // for finite frequency, construct it so that phase is w.r.t. the centre of the cavity
423 // and that it's 0 by default
424 G4double tOffset = 0;
425 if (BDS::IsFinite(modulatorInfo.tOffset)) // use the one specified
426 {tOffset = modulatorInfo.tOffset;}
427 else // this gives 0 phase at the middle of cavity assuming relativistic particle with v = c
428 {tOffset = synchronousT0;}
429
430 G4double globalPhase = CalculateGlobalPhase(modulatorInfo.frequency, tOffset);
431 return globalPhase;
432}
433
435 const G4String& parameterNameForError) const
436{
437 G4double result = 0;
438 try
439 {result = std::stod(value);}
440 catch (std::exception& e)
441 {
442 G4String msg(e.what());
443 G4String baseMsg = "Unable to interpret value (\"" + value + "\" of parameter \"";
444 baseMsg += parameterNameForError + "\" as a number: ";
445 throw BDSException(__METHOD_NAME__, baseMsg + msg);
446 }
447 return result;
448}
449
451 const G4String& fieldParameters,
452 G4double& poleTipRadius) const
453{
454 // use function from BDSUtilities to process user params string into
455 // map of strings and values.
456 std::map<G4String, G4String> map = BDS::GetUserParametersMap(fieldParameters, '=');
457
458 for (const auto& keyValue : map)
459 {
460 if (BDSMagnetStrength::ValidKey(keyValue.first))
461 {
462 G4double value = ConvertToDoubleWithException(keyValue.second, keyValue.first);
463 (*st)[keyValue.first] = value * BDSMagnetStrength::Unit(keyValue.first);
464 }
465 else if (keyValue.first == "poletipradius")
466 {poleTipRadius = ConvertToDoubleWithException(keyValue.second, keyValue.first) * CLHEP::m;}
467 else
468 {
469 G4String msg = "Invalid key \"" + keyValue.first + "\" for field parameters. ";
470 msg += "Acceptable parameters are: \n";
471 const std::vector<G4String>& allKeys = BDSMagnetStrength::AllKeys();
472 for (G4int i = 0; i < (G4int)allKeys.size(); i++)
473 {
474 msg += allKeys[i] + ", ";
475 if ((i % 10 == 0) && (i > 0))
476 {msg += "\n";}
477 }
478 throw BDSException(__METHOD_NAME__, msg);
479 }
480 }
481}
482
484{
485 // Here we test if the string is empty and return nullptr. We do this so
486 // this method can be used without exiting when no key is specified at all.
487 // If a key is given and not found, then that requires the users attention.
488 if (name.empty())
489 {return nullptr;}
490 auto result = parserDefinitions.find(name);
491 if (result == parserDefinitions.end())
492 {// not a valid key
493 G4cerr << __METHOD_NAME__ << "\"" << name << "\" is not a valid field specifier" << G4endl;
494 G4cout << "Defined field specifiers are:" << G4endl;
495 for (const auto& it : parserDefinitions)
496 {G4cout << "\"" << it.first << "\"" << G4endl;}
497 throw BDSException(__METHOD_NAME__, "invalid field name");
498 }
499 return result->second;
500}
501
503{
504 if (modulatorName.empty())
505 {return nullptr;}
506
507 auto search = parserModulatorDefinitions.find(modulatorName);
508 if (search == parserModulatorDefinitions.end())
509 {
510 G4cerr << __METHOD_NAME__ << "\"" << modulatorName << "\" is not a valid modulator definition name" << G4endl;
511 G4cout << "Defined modulator definitions are:" << G4endl;
512 for (const auto& it : parserModulatorDefinitions)
513 {G4cout << "\"" << it.first << "\"" << G4endl;}
514 throw BDSException(__METHOD_NAME__, "invalid modulator name");
515 }
516 else
517 {return search->second;}
518}
519
521 const BDSMagnetStrength* scalingStrength,
522 const G4String& scalingKey)
523{
524 // Forward on to delegate functions for the main types of field
525 // such as E, EM and Magnetic
526 BDSFieldObjects* field = nullptr;
527
528 if (info.FieldType() == BDSFieldType::none)
529 {return field;} // as nullptr
530
532 try
533 {
534 switch (clas.underlying())
535 {
536 case BDSFieldClassType::magnetic:
537 {field = CreateFieldMag(info, scalingStrength, scalingKey); break;}
538 case BDSFieldClassType::electromagnetic:
539 {field = CreateFieldEM(info); break;}
540 case BDSFieldClassType::electric:
541 {field = CreateFieldE(info); break;}
542 case BDSFieldClassType::irregular:
543 {field = CreateFieldIrregular(info); break;}
544 default:
545 {break;} // this will return nullptr
546 }
547 }
548 catch (BDSException& e)
549 {
550 e.AppendToMessage("\nProblem with field possibly named \"" + info.NameOfParserDefinition() + "\"");
551 throw e;
552 }
553 return field;
554}
555
557{
558 BDSInterpolatorType result;
559 switch (numberOfDimensions)
560 {
561 case 1:
562 {result = BDSInterpolatorType::cubic1d; break;}
563 case 2:
564 {result = BDSInterpolatorType::cubic2d; break;}
565 case 3:
566 {result = BDSInterpolatorType::cubic3d; break;}
567 case 4:
568 {result = BDSInterpolatorType::cubic4d; break;}
569 default:
570 {throw BDSException(__METHOD_NAME__, "unsupported number of dimensions " + std::to_string(numberOfDimensions));}
571 }
572 return result;
573}
574
576 const BDSMagnetStrength* scalingStrength,
577 const G4String& scalingKey)
578{
579 const BDSMagnetStrength* strength = info.MagnetStrength();
580 BDSFieldMag* field = CreateFieldMagRaw(info, scalingStrength, scalingKey);
581 if (!field)
582 {return nullptr;} // return nullptr of right type
583
584 BDSFieldMag* resultantField = field;
585 // Optionally provide local to global transform using curvilinear coordinate system.
587 {resultantField = new BDSFieldMagGlobalPlacement(field);}
588 else if (info.ProvideGlobal())
589 {resultantField = new BDSFieldMagGlobal(field);}
590
591 // Always this equation of motion for magnetic (only) fields
592 BDSMagUsualEqRhs* eqOfM = new BDSMagUsualEqRhs(resultantField);
593
594 // Create appropriate integrator
595 G4MagIntegratorStepper* integrator = CreateIntegratorMag(info, eqOfM, strength);
596
597 BDSFieldObjects* completeField = new BDSFieldObjects(&info, resultantField, eqOfM, integrator);
598 return completeField;
599}
600
602 const BDSMagnetStrength* scalingStrength,
603 const G4String& scalingKey)
604{
605 BDSFieldMag* field = nullptr;
606 const BDSMagnetStrength* strength = info.MagnetStrength();
607 G4double brho = info.BRho();
608 G4double poleTipRadius = info.PoleTipRadius();
609 G4double beamPipeRadius = info.BeamPipeRadius();
610 switch (info.FieldType().underlying())
611 {
612 case BDSFieldType::bmap1d:
613 case BDSFieldType::bmap2d:
614 case BDSFieldType::bmap3d:
615 case BDSFieldType::bmap4d:
616 case BDSFieldType::mokka:
617 {
619 scalingStrength,
620 scalingKey);
621 if (ff)
622 {info.UpdateUserLimitsLengthMaximumStepSize(ff->SmallestSpatialStep(), true);}
623 field = ff;
624 break;
625 }
626 case BDSFieldType::bfieldzero:
627 {field = new BDSFieldMagZero(); break;}
628 case BDSFieldType::solenoid:
629 case BDSFieldType::dipole:
630 case BDSFieldType::dipole3d:
631 {field = new BDSFieldMagDipole(strength); break;}
632 case BDSFieldType::solenoidsheet:
633 {field = new BDSFieldMagSolenoidSheet(strength, poleTipRadius); break;}
634 case BDSFieldType::quadrupole:
635 {field = new BDSFieldMagQuadrupole(strength, brho); break;}
636 case BDSFieldType::undulator:
637 {field = new BDSFieldMagUndulator(strength, beamPipeRadius); break;}
638 case BDSFieldType::dipolequadrupole:
639 {field = new BDSFieldMagDipoleQuadrupole(strength, brho); break;}
640 case BDSFieldType::sextupole:
641 {field = new BDSFieldMagSextupole(strength, brho); break;}
642 case BDSFieldType::octupole:
643 {field = new BDSFieldMagOctupole(strength, brho); break;}
644 case BDSFieldType::decapole:
645 {field = new BDSFieldMagDecapole(strength, brho); break;}
646 case BDSFieldType::multipole:
647 {field = new BDSFieldMagMultipole(strength, brho); break;}
648 case BDSFieldType::muonspoiler:
649 {field = new BDSFieldMagMuonSpoiler(strength, brho); break;}
650 case BDSFieldType::skewquadrupole:
651 {field = new BDSFieldMagSkewOwn(new BDSFieldMagQuadrupole(strength, brho), CLHEP::pi/4.); break;}
652 case BDSFieldType::skewsextupole:
653 {field = new BDSFieldMagSkewOwn(new BDSFieldMagSextupole(strength, brho), CLHEP::pi/6.); break;}
654 case BDSFieldType::skewoctupole:
655 {field = new BDSFieldMagSkewOwn(new BDSFieldMagOctupole(strength, brho), CLHEP::pi/8.); break;}
656 case BDSFieldType::skewdecapole:
657 {field = new BDSFieldMagSkewOwn(new BDSFieldMagDecapole(strength, brho), CLHEP::pi/10.); break;}
658 case BDSFieldType::multipoleouterdipole:
659 {// suitable only for querying transversely in x,y - no 3d nature
660 BDSFieldMag* innerField = new BDSFieldMagDipole(strength);
661 G4bool positiveField = (*strength)["field"] < 0; // convention for dipoles - "positive"
662 if (useOldMultipoleOuterFields)
663 {field = new BDSFieldMagMultipoleOuterOld(1, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
664 else // positive field for a dipole has no meaning for this class - fix at false
665 {field = new BDSFieldMagMultipoleOuter(1, poleTipRadius, innerField, false, brho, GetOuterScaling(strength));}
666 delete innerField; // no longer required
667 break;
668 }
669 case BDSFieldType::multipoleouterquadrupole:
670 {
671 BDSFieldMag* innerField = new BDSFieldMagQuadrupole(strength, brho);
672 G4bool positiveField = (*strength)["k1"] > 0;
673 if (useOldMultipoleOuterFields)
674 {field = new BDSFieldMagMultipoleOuterOld(2, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
675 else
676 {field = new BDSFieldMagMultipoleOuter(2, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
677 delete innerField; // no longer required
678 break;
679 }
680 case BDSFieldType::multipoleoutersextupole:
681 {
682 BDSFieldMag* innerField = new BDSFieldMagSextupole(strength, brho);
683 G4bool positiveField = (*strength)["k2"] > 0;
684 if (useOldMultipoleOuterFields)
685 {field = new BDSFieldMagMultipoleOuterOld(3, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
686 else
687 {field = new BDSFieldMagMultipoleOuter(3, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
688 delete innerField; // no longer required
689 break;
690 }
691 case BDSFieldType::multipoleouteroctupole:
692 {
693 BDSFieldMag* innerField = new BDSFieldMagOctupole(strength, brho);
694 G4bool positiveField = (*strength)["k3"] > 0;
695 if (useOldMultipoleOuterFields)
696 {field = new BDSFieldMagMultipoleOuterOld(4, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
697 else
698 {field = new BDSFieldMagMultipoleOuter(4, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
699 delete innerField; // no longer required
700 break;
701 }
702 case BDSFieldType::multipoleouterdecapole:
703 {
704 BDSFieldMag* innerField = new BDSFieldMagDecapole(strength, brho);
705 G4bool positiveField = (*strength)["k4"] > 0;
706 if (useOldMultipoleOuterFields)
707 {field = new BDSFieldMagMultipoleOuterOld(5, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
708 else
709 {field = new BDSFieldMagMultipoleOuter(5, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
710 delete innerField; // no longer required
711 break;
712 }
713 case BDSFieldType::skewmultipoleouterquadrupole:
714 {
715 BDSFieldMag* innerField = new BDSFieldMagQuadrupole(strength, brho);
716 G4bool positiveField = (*strength)["k1"] > 0;
717 BDSFieldMag* normalField;
718 if (useOldMultipoleOuterFields)
719 {normalField = new BDSFieldMagMultipoleOuterOld(2, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
720 else
721 {normalField = new BDSFieldMagMultipoleOuter(2, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
722 field = new BDSFieldMagSkewOwn(normalField, CLHEP::pi/4.);
723 delete innerField; // no longer required
724 break;
725 }
726 case BDSFieldType::skewmultipoleoutersextupole:
727 {
728 BDSFieldMag* innerField = new BDSFieldMagSextupole(strength, brho);
729 G4bool positiveField = (*strength)["k2"] > 0;
730 BDSFieldMag* normalField;
731 if (useOldMultipoleOuterFields)
732 {normalField = new BDSFieldMagMultipoleOuterOld(3, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
733 else
734 {normalField = new BDSFieldMagMultipoleOuter(3, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
735 field = new BDSFieldMagSkewOwn(normalField, CLHEP::pi/6.);
736 delete innerField; // no longer required
737 break;
738 }
739 case BDSFieldType::skewmultipoleouteroctupole:
740 {
741 BDSFieldMag* innerField = new BDSFieldMagOctupole(strength, brho);
742 G4bool positiveField = (*strength)["k3"] > 0;
743 BDSFieldMag* normalField;
744 if (useOldMultipoleOuterFields)
745 {normalField = new BDSFieldMagMultipoleOuterOld(4, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
746 else
747 {normalField = new BDSFieldMagMultipoleOuter(4, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
748 field = new BDSFieldMagSkewOwn(normalField, CLHEP::pi/8.);
749 delete innerField; // no longer required
750 break;
751 }
752 case BDSFieldType::skewmultipoleouterdecapole:
753 {
754 BDSFieldMag* innerField = new BDSFieldMagDecapole(strength, brho);
755 G4bool positiveField = (*strength)["k4"] > 0;
756 BDSFieldMag* normalField;
757 if (useOldMultipoleOuterFields)
758 {normalField = new BDSFieldMagMultipoleOuterOld(5, poleTipRadius, innerField, positiveField, GetOuterScaling(strength));}
759 else
760 {normalField = new BDSFieldMagMultipoleOuter(5, poleTipRadius, innerField, positiveField, brho, GetOuterScaling(strength));}
761 field = new BDSFieldMagSkewOwn(normalField, CLHEP::pi/10.);
762 delete innerField; // no longer required
763 break;
764 }
765 case BDSFieldType::multipoleouterdipole3d:
766 {
767 if (useOldMultipoleOuterFields)
768 {field = new BDSFieldMagDipoleOuterOld(strength, poleTipRadius, GetOuterScaling(strength));}
769 else
770 {field = new BDSFieldMagDipoleOuter(strength, poleTipRadius, GetOuterScaling(strength));}
771 break;
772 }
773 case BDSFieldType::multipoleouterdipolelhc:
774 {
775 BDSFieldMag* innerField = new BDSFieldMagDipole(strength);
776 G4bool positiveField = (*strength)["field"] < 0; // convention for dipoles - "positive"
777 G4bool positiveField2 = (*strength)["angle"] > 0;
779 if (useOldMultipoleOuterFields)
780 {
781 field = new BDSFieldMagMultipoleOuterDualOld(1, poleTipRadius, innerField, positiveField, dx,
782 info.SecondFieldOnLeft(), GetOuterScaling(strength));
783 }
784 else
785 {
786 field = new BDSFieldMagMultipoleOuterDual(1, poleTipRadius, innerField, positiveField2, brho, dx,
787 info.SecondFieldOnLeft(), GetOuterScaling(strength));
788 }
789 delete innerField; // no longer required
790 break;
791 }
792 case BDSFieldType::multipoleouterquadrupolelhc:
793 {
794 BDSFieldMag* innerField = new BDSFieldMagQuadrupole(strength, brho);
795 G4bool positiveField = (*strength)["k1"] > 0;
797 if (useOldMultipoleOuterFields)
798 {
799 field = new BDSFieldMagMultipoleOuterDualOld(2, poleTipRadius, innerField, positiveField, dx,
800 info.SecondFieldOnLeft(), GetOuterScaling(strength));
801 }
802 else
803 {
804 field = new BDSFieldMagMultipoleOuterDual(2, poleTipRadius, innerField, positiveField, brho, dx,
805 info.SecondFieldOnLeft(), GetOuterScaling(strength));
806 }
807 delete innerField; // no longer required
808 break;
809 }
810 case BDSFieldType::multipoleoutersextupolelhc:
811 {
812 BDSFieldMag* innerField = new BDSFieldMagSextupole(strength, brho);
813 G4bool positiveField = (*strength)["k2"] > 0;
815 if (useOldMultipoleOuterFields)
816 {
817 field = new BDSFieldMagMultipoleOuterDualOld(3, poleTipRadius, innerField, positiveField, dx,
818 info.SecondFieldOnLeft(), GetOuterScaling(strength));
819 }
820 else
821 {
822 field = new BDSFieldMagMultipoleOuterDual(3, poleTipRadius, innerField, positiveField, dx, brho,
823 info.SecondFieldOnLeft(), GetOuterScaling(strength));
824 }
825 delete innerField; // no longer required
826 break;
827 }
828 case BDSFieldType::paralleltransporter:
829 default:
830 {// there is no need for case BDSFieldType::none as this won't be used in this function.
831 break;
832 }
833 }
834
835 // Set transform for local geometry offset
836 // Do this before wrapping in global converter BDSFieldMagGlobal so that the sub-field
837 // has it and not the global wrapper.
838 if (field)
839 {
840 field->SetTransform(info.TransformComplete());
841
842 if (info.ModulatorInfo())
843 {
844 BDSModulator* modulator = CreateModulator(info.ModulatorInfo(), info);
845 if (modulator->VariesWithTime() && field->TimeVarying())
846 {BDS::Warning(__METHOD_NAME__, "using a time varying modulation on a time varying field for field \"" + info.NameOfParserDefinition() + "\"");}
847 field->SetModulator(modulator);
849 }
850 }
851
852 if (!info.MagneticSubFieldName().empty() && field)
853 {
854 // set the transform of the 'main' field to only the transform defined in that field definition
855 field->SetTransform(info.Transform());
856
857 auto mainField = dynamic_cast<BDSFieldMagInterpolated*>(field);
858 if (!mainField)
859 {throw BDSException(__METHOD_NAME__, "subfield specified for non-field map type field - not supported");}
860
861 BDSFieldInfo* subFieldRecipe = new BDSFieldInfo(*(GetDefinition(info.MagneticSubFieldName())));
862 BDSFieldMag* subFieldRaw = CreateFieldMagRaw(*subFieldRecipe, scalingStrength, scalingKey);
863 auto subField = dynamic_cast<BDSFieldMagInterpolated*>(subFieldRaw);
864 if (!subField)
865 {throw BDSException(__METHOD_NAME__, "subfield type is not a field map type field - not supported");}
866 field = new BDSFieldMagInterpolated2Layer(mainField, subField);
867 // the transform goes beamline transform to the 2Layer class, then inside that the individual field transforms
868 field->SetTransform(info.TransformBeamline());
869 delete subFieldRecipe;
870 }
871
872 return field;
873}
874
876{
877 BDSFieldEM* field = nullptr;
878 switch (info.FieldType().underlying())
879 {
880 case BDSFieldType::rfpillbox:
881 {field = new BDSFieldEMRFCavity(info.MagnetStrength(), info.BRho()); break;}
882 case BDSFieldType::ebmap1d:
883 case BDSFieldType::ebmap2d:
884 case BDSFieldType::ebmap3d:
885 case BDSFieldType::ebmap4d:
886 {
888 if (ff)
889 {info.UpdateUserLimitsLengthMaximumStepSize(ff->SmallestSpatialStep(), true);}
890 field = ff;
891 break;
892 }
893 case BDSFieldType::ebfieldzero:
894 {field = new BDSFieldEMZero(); break;}
895 default:
896 return nullptr;
897 break;
898 }
899
900 // Set transform for local geometry offset
901 if (field)
902 {
903 field->SetTransform(info.TransformComplete());
904
905 if (info.ModulatorInfo())
906 {
907 BDSModulator* modulator = CreateModulator(info.ModulatorInfo(), info);
908 if (modulator->VariesWithTime() && field->TimeVarying())
909 {BDS::Warning(__METHOD_NAME__, "using a time varying modulation on a time varying field for field \"" + info.NameOfParserDefinition() + "\"");}
910 field->SetModulator(modulator);
912 }
913 }
914
915 if (!field)
916 {return nullptr;}
917
918 // Optionally provide local to global transform using curvilinear coordinate system.
919 BDSFieldEM* resultantField = field;
921 {resultantField = new BDSFieldEMGlobalPlacement(field);}
922 else if (info.ProvideGlobal())
923 {resultantField = new BDSFieldEMGlobal(field);}
924
925 // Equation of motion for em fields
926 G4EqMagElectricField* eqOfM = new G4EqMagElectricField(resultantField);
927
928 // Create appropriate integrator
929 G4MagIntegratorStepper* integrator = CreateIntegratorEM(info, eqOfM);
930
931 BDSFieldObjects* completeField = new BDSFieldObjects(&info, resultantField, eqOfM, integrator);
932 return completeField;
933}
934
936{
937 BDSFieldE* field = CreateFieldERaw(info);
938 if (!field)
939 {return nullptr;}
940
941 // Optionally provide local to global transform using curvilinear coordinate system.
942 BDSFieldE* resultantField = field;
944 {resultantField = new BDSFieldEGlobalPlacement(field);}
945 else if (info.ProvideGlobal())
946 {resultantField = new BDSFieldEGlobal(field);}
947
948 // Equation of motion for em fields
949 G4EqMagElectricField* eqOfM = new G4EqMagElectricField(resultantField);
950
951 // Create appropriate integrator
952 G4MagIntegratorStepper* integrator = CreateIntegratorE(info, eqOfM);
953
954 BDSFieldObjects* completeField = new BDSFieldObjects(&info, resultantField, eqOfM, integrator);
955 return completeField;
956}
957
959{
960 BDSFieldE* field = nullptr;
961 switch (info.FieldType().underlying())
962 {
963 case BDSFieldType::rfconstantinx:
964 case BDSFieldType::rfconstantiny:
965 case BDSFieldType::rfconstantinz:
966 {field = new BDSFieldESinusoid(info.MagnetStrength(), info.BRho()); break;}
967 case BDSFieldType::emap1d:
968 case BDSFieldType::emap2d:
969 case BDSFieldType::emap3d:
970 case BDSFieldType::emap4d:
971 {
973 if (ff)
974 {info.UpdateUserLimitsLengthMaximumStepSize(ff->SmallestSpatialStep(), true);}
975 field = ff;
976 break;
977 }
978 case BDSFieldType::efieldzero:
979 {field = new BDSFieldEZero(); break;}
980 default:
981 return nullptr;
982 break;
983 }
984
985 // Set transform for local geometry offset
986 if (field)
987 {
988 field->SetTransform(info.TransformComplete());
989
990 if (info.ModulatorInfo())
991 {
992 BDSModulator* modulator = CreateModulator(info.ModulatorInfo(), info);
993 if (modulator->VariesWithTime() && field->TimeVarying())
994 {BDS::Warning(__METHOD_NAME__, "using a time varying modulation on a time varying field for field \"" + info.NameOfParserDefinition() + "\"");}
995 field->SetModulator(modulator);
997 }
998 }
999
1000 if (!info.ElectricSubFieldName().empty() && field)
1001 {
1002 // set the transform of the 'main' field to only the transform defined in that field definition
1003 field->SetTransform(info.Transform());
1004
1005 auto mainField = dynamic_cast<BDSFieldEInterpolated*>(field);
1006 if (!mainField)
1007 {throw BDSException(__METHOD_NAME__, "subfield specified for non-field map type field - not supported");}
1008
1009 BDSFieldInfo* subFieldRecipe = new BDSFieldInfo(*(GetDefinition(info.ElectricSubFieldName())));
1010 BDSFieldE* subFieldRaw = CreateFieldERaw(*subFieldRecipe);
1011 auto subField = dynamic_cast<BDSFieldEInterpolated*>(subFieldRaw);
1012 if (!subField)
1013 {throw BDSException(__METHOD_NAME__, "subfield type is not a field map type field - not supported");}
1014 field = new BDSFieldEInterpolated2Layer(mainField, subField);
1015 // the transform goes beamline transform to the 2Layer class, then inside that the individual field transforms
1016 field->SetTransform(info.TransformBeamline());
1017 delete subFieldRecipe;
1018 }
1019
1020 return field;
1021}
1022
1024{
1025 // special routine for each special / irregular field
1026 BDSFieldObjects* result = nullptr;
1027 switch (info.FieldType().underlying())
1028 {
1029 case BDSFieldType::teleporter:
1030 {result = CreateTeleporter(info); break;}
1031 case BDSFieldType::rmatrix:
1032 {result = CreateRMatrix(info); break;}
1033 case BDSFieldType::cavityfringe:
1034 {result = CreateCavityFringe(info); break;}
1035 case BDSFieldType::paralleltransporter:
1036 {result = CreateParallelTransport(info); break;}
1037 default:
1038 {break;}
1039 }
1040 return result;
1041}
1042
1043G4MagIntegratorStepper* BDSFieldFactory::CreateIntegratorMag(const BDSFieldInfo& info,
1044 G4Mag_EqRhs* eqOfM,
1045 const BDSMagnetStrength* strength)
1046{
1047 const G4double minimumRadiusOfCurvature = 10*CLHEP::cm;
1048 G4double brho = info.BRho();
1049 G4MagIntegratorStepper* integrator = nullptr;
1050 // these ones can only be used for magnetic field
1051 switch (info.IntegratorType().underlying())
1052 {
1053 case BDSIntegratorType::solenoid:
1054 integrator = new BDSIntegratorSolenoid(strength, brho, eqOfM); break;
1055 case BDSIntegratorType::dipolerodrigues:
1056 integrator = new BDSIntegratorDipoleRodrigues(strength, brho, eqOfM); break;
1057 case BDSIntegratorType::dipolerodrigues2:
1058 integrator = new BDSIntegratorDipoleRodrigues2(eqOfM, minimumRadiusOfCurvature); break;
1059 case BDSIntegratorType::dipolematrix:
1060 integrator = new BDSIntegratorDipoleQuadrupole(strength, brho, eqOfM, minimumRadiusOfCurvature, designParticle, info.Tilt()); break;
1061 case BDSIntegratorType::quadrupole:
1062 integrator = new BDSIntegratorQuadrupole(strength, brho, eqOfM, minimumRadiusOfCurvature); break;
1063 case BDSIntegratorType::sextupole:
1064 integrator = new BDSIntegratorSextupole(strength, brho, eqOfM); break;
1065 case BDSIntegratorType::octupole:
1066 integrator = new BDSIntegratorOctupole(strength, brho, eqOfM); break;
1067 case BDSIntegratorType::decapole:
1068 integrator = new BDSIntegratorDecapole(strength, brho, eqOfM); break;
1069 case BDSIntegratorType::multipolethin:
1070 integrator = new BDSIntegratorMultipoleThin(strength, brho, eqOfM); break;
1071 case BDSIntegratorType::dipolefringe:
1072 integrator = new BDSIntegratorDipoleFringe(strength, brho, eqOfM, minimumRadiusOfCurvature, info.Tilt()); break;
1073 case BDSIntegratorType::dipolefringescaling:
1074 integrator = new BDSIntegratorDipoleFringeScaling(strength, brho, eqOfM, minimumRadiusOfCurvature, info.Tilt()); break;
1075 case BDSIntegratorType::euler:
1076 integrator = new BDSIntegratorEuler(eqOfM); break;
1077 case BDSIntegratorType::kickerthin:
1078 integrator = new BDSIntegratorKickerThin(strength, brho, eqOfM, minimumRadiusOfCurvature); break;
1079 case BDSIntegratorType::g4rk4minimumstep:
1080 integrator = new BDSIntegratorG4RK4MinStep(eqOfM, BDSGlobalConstants::Instance()->ChordStepMinimumYoke()); break;
1081 case BDSIntegratorType::rmatrixthin:
1082 integrator = new BDSIntegratorRMatrixThin(strength,eqOfM, info.BeamPipeRadius()); break;
1083 case BDSIntegratorType::cavityfringe:
1084 integrator = new BDSIntegratorCavityFringe(strength,eqOfM, info.BeamPipeRadius()); break;
1085 case BDSIntegratorType::g4constrk4:
1086 integrator = new G4ConstRK4(eqOfM); break;
1087 case BDSIntegratorType::g4exacthelixstepper:
1088 integrator = new G4ExactHelixStepper(eqOfM); break;
1089 case BDSIntegratorType::g4helixexpliciteuler:
1090 integrator = new G4HelixExplicitEuler(eqOfM); break;
1091 case BDSIntegratorType::g4helixheum:
1092 integrator = new G4HelixHeum(eqOfM); break;
1093 case BDSIntegratorType::g4heliximpliciteuler:
1094 integrator = new G4HelixImplicitEuler(eqOfM); break;
1095 case BDSIntegratorType::g4helixmixedstepper:
1096 integrator = new G4HelixMixedStepper(eqOfM); break;
1097 case BDSIntegratorType::g4helixsimplerunge:
1098 integrator = new G4HelixSimpleRunge(eqOfM); break;
1099 case BDSIntegratorType::g4nystromrk4:
1100 integrator = new G4NystromRK4(eqOfM); break;
1101 case BDSIntegratorType::g4rkg3stepper:
1102 integrator = new G4RKG3_Stepper(eqOfM); break;
1103 case BDSIntegratorType::g4cashkarprkf45:
1104 case BDSIntegratorType::g4classicalrk4:
1105 case BDSIntegratorType::g4expliciteuler:
1106 case BDSIntegratorType::g4impliciteuler:
1107 case BDSIntegratorType::g4simpleheum:
1108 case BDSIntegratorType::g4simplerunge:
1109#if G4VERSION_NUMBER > 1029
1110 case BDSIntegratorType::g4bogackishampine23:
1111 case BDSIntegratorType::g4bogackishampine45:
1112 case BDSIntegratorType::g4dolomcprirk34:
1113 case BDSIntegratorType::g4dormandprince745:
1114 case BDSIntegratorType::g4dormandprincerk56:
1115 case BDSIntegratorType::g4tsitourasrk45:
1116#endif
1117#if G4VERSION_NUMBER > 1039
1118 case BDSIntegratorType::g4dormandprincerk78:
1119 case BDSIntegratorType::g4rk547feq1:
1120 case BDSIntegratorType::g4rk547feq2:
1121 case BDSIntegratorType::g4rk547feq3:
1122#endif
1123 integrator = CreateIntegratorEM(info, (G4EquationOfMotion*)eqOfM); break;
1124 default:
1125 break; // returns nullptr;
1126 }
1127
1128 return integrator;
1129}
1130
1131G4MagIntegratorStepper* BDSFieldFactory::CreateIntegratorEM(const BDSFieldInfo& info,
1132 G4EquationOfMotion* eqOfM)
1133{
1134 G4MagIntegratorStepper* integrator = nullptr;
1135 switch (info.IntegratorType().underlying())
1136 {
1137 // do the EM ones first, then complain
1138 case BDSIntegratorType::g4cashkarprkf45:
1139 integrator = new G4CashKarpRKF45(eqOfM, 8); break;
1140 case BDSIntegratorType::g4classicalrk4:
1141 integrator = new G4ClassicalRK4(eqOfM, 8); break;
1142 case BDSIntegratorType::g4expliciteuler:
1143 integrator = new G4ExplicitEuler(eqOfM, 8); break;
1144 case BDSIntegratorType::g4impliciteuler:
1145 integrator = new G4ImplicitEuler(eqOfM, 8); break;
1146 case BDSIntegratorType::g4simpleheum:
1147 integrator = new G4SimpleHeum(eqOfM, 8); break;
1148 case BDSIntegratorType::g4simplerunge:
1149 integrator = new G4SimpleRunge(eqOfM, 8); break;
1150#if G4VERSION_NUMBER > 1029
1151 case BDSIntegratorType::g4bogackishampine23:
1152 {integrator = new G4BogackiShampine45(eqOfM, 8); break;}
1153 case BDSIntegratorType::g4bogackishampine45:
1154 {integrator = new G4BogackiShampine45(eqOfM, 8); break;}
1155 case BDSIntegratorType::g4dolomcprirk34:
1156 {integrator = new G4DoLoMcPriRK34(eqOfM, 8); break;}
1157 case BDSIntegratorType::g4dormandprince745:
1158 {integrator = new G4DormandPrince745(eqOfM, 8); break;}
1159 case BDSIntegratorType::g4dormandprincerk56:
1160 {integrator = new G4DormandPrinceRK56(eqOfM, 8); break;}
1161 case BDSIntegratorType::g4tsitourasrk45:
1162 {integrator = new G4TsitourasRK45(eqOfM, 8); break;}
1163#endif
1164#if G4VERSION_NUMBER > 1039
1165 case BDSIntegratorType::g4dormandprincerk78:
1166 {integrator = new G4DormandPrinceRK78(eqOfM, 8); break;}
1167 case BDSIntegratorType::g4rk547feq1:
1168 {integrator = new G4RK547FEq1(eqOfM, 8); break;}
1169 case BDSIntegratorType::g4rk547feq2:
1170 {integrator = new G4RK547FEq2(eqOfM, 8); break;}
1171 case BDSIntegratorType::g4rk547feq3:
1172 {integrator = new G4RK547FEq3(eqOfM, 8); break;}
1173#endif
1174 case BDSIntegratorType::solenoid:
1175 case BDSIntegratorType::dipolerodrigues:
1176 case BDSIntegratorType::quadrupole:
1177 case BDSIntegratorType::sextupole:
1178 case BDSIntegratorType::octupole:
1179 case BDSIntegratorType::decapole:
1180 case BDSIntegratorType::dipolefringe:
1181 case BDSIntegratorType::g4constrk4:
1182 case BDSIntegratorType::g4exacthelixstepper:
1183 case BDSIntegratorType::g4helixexpliciteuler:
1184 case BDSIntegratorType::g4helixheum:
1185 case BDSIntegratorType::g4heliximpliciteuler:
1186 case BDSIntegratorType::g4helixmixedstepper:
1187 case BDSIntegratorType::g4helixsimplerunge:
1188 case BDSIntegratorType::g4nystromrk4:
1189 case BDSIntegratorType::g4rkg3stepper:
1190 {
1191 G4cerr << "Error: integrator \"" << info.IntegratorType() << "\" is not suitable for an EM field." << G4endl;
1192 G4cout << "Suitable integrators are:" << G4endl;
1193 std::vector<BDSIntegratorType> types = {
1194 BDSIntegratorType::g4cashkarprkf45,
1195 BDSIntegratorType::g4classicalrk4,
1196 BDSIntegratorType::g4expliciteuler,
1197 BDSIntegratorType::g4impliciteuler,
1198 BDSIntegratorType::g4simpleheum,
1199 BDSIntegratorType::g4simplerunge
1200#if G4VERSION_NUMBER > 1029
1201 ,
1202 BDSIntegratorType::g4bogackishampine23,
1203 BDSIntegratorType::g4bogackishampine45,
1204 BDSIntegratorType::g4dolomcprirk34,
1205 BDSIntegratorType::g4dormandprince745,
1206 BDSIntegratorType::g4dormandprincerk56,
1207 BDSIntegratorType::g4tsitourasrk45
1208#endif
1209#if G4VERSION_NUMBER > 1039
1210 ,
1211 BDSIntegratorType::g4dormandprincerk78,
1212 BDSIntegratorType::g4rk547feq1,
1213 BDSIntegratorType::g4rk547feq2,
1214 BDSIntegratorType::g4rk547feq3
1215#endif
1216 };
1217 for (auto type : types)
1218 {G4cout << type << G4endl;}
1219 throw BDSException(__METHOD_NAME__, "invalid integrator type");
1220 }
1221 default:
1222 break; // returns nullptr;
1223 }
1224 return integrator;
1225}
1226
1227G4MagIntegratorStepper* BDSFieldFactory::CreateIntegratorE(const BDSFieldInfo& info,
1228 G4EquationOfMotion* eqOfM)
1229{
1230 return CreateIntegratorEM(info,eqOfM);
1231}
1232
1234{
1235 G4MagneticField* bGlobalField = new BDSFieldMagZero();
1236 G4Mag_EqRhs* bEqOfMotion = new G4Mag_UsualEqRhs(bGlobalField);
1237
1238 G4MagIntegratorStepper* integrator;
1239 auto mapfile = BDSGlobalConstants::Instance()->PTCOneTurnMapFileName(); // TBC - this shouldn't come from global constants
1240 BDSPTCOneTurnMap* otm = nullptr;
1241
1242 if (!mapfile.empty())
1243 {
1244 otm = new BDSPTCOneTurnMap(mapfile, designParticle);
1246 }
1247
1248 integrator = new BDSIntegratorTeleporter(bEqOfMotion, info.TransformComplete(),
1249 (*info.MagnetStrength())["length"],
1250 otm);
1251
1252 BDSFieldObjects* completeField = new BDSFieldObjects(&info, bGlobalField,
1253 bEqOfMotion, integrator);
1254 return completeField;
1255}
1256
1258{
1259 G4MagneticField* bGlobalField = new BDSFieldMagZero();
1260 G4Mag_EqRhs* bEqOfMotion = new G4Mag_UsualEqRhs(bGlobalField);
1261 G4MagIntegratorStepper* integrator = new BDSIntegratorRMatrixThin(info.MagnetStrength(),bEqOfMotion,0.95*info.BeamPipeRadius());
1262 BDSFieldObjects* completeField = new BDSFieldObjects(&info, bGlobalField,
1263 bEqOfMotion, integrator);
1264 return completeField;
1265}
1266
1268{
1269 BDSFieldMag* bGlobalField = new BDSFieldMagZero();
1270 BDSMagUsualEqRhs* bEqOfMotion = new BDSMagUsualEqRhs(bGlobalField);
1271 G4MagIntegratorStepper* integrator = new BDSIntegratorCavityFringe(info.MagnetStrength(),bEqOfMotion,0.95*info.BeamPipeRadius());
1272 BDSFieldObjects* completeField = new BDSFieldObjects(&info, bGlobalField,
1273 bEqOfMotion, integrator);
1274 return completeField;
1275}
1276
1278{
1279 G4MagneticField* bGlobalField = new BDSFieldMagZero();
1280 G4Mag_EqRhs* bEqOfMotion = new G4Mag_UsualEqRhs(bGlobalField);
1281 G4MagIntegratorStepper* integrator = new BDSIntegratorParallelTransport(bEqOfMotion);
1282 BDSFieldObjects* completeField = new BDSFieldObjects(&info, bGlobalField,
1283 bEqOfMotion, integrator);
1284 return completeField;
1285}
1286
1288{
1289 G4double result = 1.0;
1290 if (st->KeyHasBeenSet("scalingOuter"))
1291 {result = (*st)["scalingOuter"];}
1292 return result;
1293}
1294
1296 const BDSFieldInfo& info) const
1297{
1298 if (!modulatorRecipe)
1299 {return nullptr;}
1300 BDSModulator* result = nullptr;
1301 try
1302 {
1303 switch (modulatorRecipe->modulatorType.underlying())
1304 {
1305 case BDSModulatorType::sint:
1306 {
1307 G4double globalPhase = CalculateGlobalPhase(*modulatorRecipe, info);
1308 result = new BDSModulatorSinT(modulatorRecipe->frequency,
1309 globalPhase,
1310 modulatorRecipe->amplitudeOffset,
1311 modulatorRecipe->scale);
1312 break;
1313 }
1314 case BDSModulatorType::singlobalt:
1315 {
1316 // calculate phase with no synchronous offset
1317 G4double globalPhase = BDS::IsFinite(modulatorRecipe->phase) ? modulatorRecipe->phase : CalculateGlobalPhase(modulatorRecipe->frequency, modulatorRecipe->tOffset);;
1318 result = new BDSModulatorSinT(modulatorRecipe->frequency,
1319 globalPhase,
1320 modulatorRecipe->amplitudeOffset,
1321 modulatorRecipe->scale);
1322 break;
1323 }
1324 case BDSModulatorType::tophatt:
1325 {
1326 result = new BDSModulatorTopHatT(modulatorRecipe->T0,
1327 modulatorRecipe->T1,
1328 modulatorRecipe->scale);
1329 break;
1330 }
1331 case BDSModulatorType::none:
1332 default:
1333 {break;}
1334 }
1335 }
1336 catch (BDSException& e)
1337 {
1338 G4String extraMsg = "\nProblem in field definition for component \"" + info.NameOfParserDefinition() + "\"";
1339 e.AppendToMessage(extraMsg);
1340 throw e;
1341 }
1342 return result;
1343}
G4double aper1
Public member for direct access.
General exception with possible name of object and message.
Definition: BDSException.hh:35
Wrapper class to convert to global coordinates using a navigator for placements.
A base class for electric fields in local to be used in global coordinates.
Two interpolated fields in one. One takes precedence in a subregion.
Class to provide scaling and a base class pointer for interpolator fields.
A base class for electro-magnetic fields in local to be used in global coordinates.
A base class for electro-magnetic fields in local to be used in global coordinates.
Class to provide scaling and a base class pointer for interpolator fields.
Pill box cavity electromagnetic field.
Null EM field - for special cases where we need a valid object.
Interface for BDSIM electro-magnetic fields that may or may not be local.
Definition: BDSFieldEM.hh:41
void SetModulator(BDSModulator *modulatorIn)
Set the optional modulator.
Definition: BDSFieldEM.hh:82
virtual G4bool TimeVarying() const
Definition: BDSFieldEM.hh:58
virtual void SetTransform(const G4Transform3D &transformIn)
Definition: BDSFieldEM.cc:88
A sinusoidal electric (only) field that doesn't vary with position. Uses cosine.
Null E field - for special cases where we need a valid object.
Interface for BDSIM electric fields that may or may not be local.
Definition: BDSFieldE.hh:39
virtual G4bool TimeVarying() const
Definition: BDSFieldE.hh:56
void SetModulator(BDSModulator *modulatorIn)
Set the optional modulator.
Definition: BDSFieldE.hh:77
virtual void SetTransform(const G4Transform3D &transformIn)
Definition: BDSFieldE.cc:84
Factory that produces fields and their associated objects.
G4double GetOuterScaling(const BDSMagnetStrength *st) const
Return the parameter "outerScaling" from strength st, but default to 1.
void PrepareFieldDefinitions(const std::vector< GMAD::Field > &definitions, G4double defaultBRho)
Prepare all required definitions that can be used dynamically.
void PrepareModulatorDefinitions(const std::vector< GMAD::Modulator > &definitions)
Prepare all required modulator definitions that can be used dynamically.
BDSFieldObjects * CreateFieldE(const BDSFieldInfo &info)
Create an electric field.
BDSFieldObjects * CreateFieldIrregular(const BDSFieldInfo &info)
Create an irregular (special) field.
BDSFieldObjects * CreateRMatrix(const BDSFieldInfo &info)
Create special rmatrix 'field' that applies an rmatrix.
void PrepareFieldStrengthFromParameters(BDSMagnetStrength *st, const G4String &fieldParameters, G4double &poleTipRadius) const
static BDSPrimaryGeneratorAction * primaryGeneratorAction
Cache of primary generator action.
BDSModulator * CreateModulator(const BDSModulatorInfo *modulatorRecipe, const BDSFieldInfo &info) const
Create the necessary modulator.
BDSFieldE * CreateFieldERaw(const BDSFieldInfo &info)
Creat just the electric field object.
G4double ConvertToDoubleWithException(const G4String &value, const G4String &parameterNameForError) const
Convert the string 'value' to a double. Throw an exception including the parameterNameForError if it ...
static BDSFieldFactory * Instance()
Public accessor method for singleton pattern.
BDSFieldObjects * CreateField(const BDSFieldInfo &info, const BDSMagnetStrength *scalingStrength=nullptr, const G4String &scalingKey="none")
Main interface to field factory.
BDSFieldObjects * CreateParallelTransport(const BDSFieldInfo &info)
static BDSFieldFactory * instance
Instance - singleton pattern.
BDSFieldInfo * GetDefinition(const G4String &name) const
BDSFieldObjects * CreateCavityFringe(const BDSFieldInfo &info)
Create special rf cavity fringe 'field' that applies an rmatrix.
std::map< G4String, BDSFieldInfo * > parserDefinitions
BDSFieldInfo definitions prepare from parser vector of definitions.
G4MagIntegratorStepper * CreateIntegratorMag(const BDSFieldInfo &info, G4Mag_EqRhs *eqOfM, const BDSMagnetStrength *strength)
G4MagIntegratorStepper * CreateIntegratorE(const BDSFieldInfo &info, G4EquationOfMotion *eqOfM)
BDSFieldObjects * CreateFieldMag(const BDSFieldInfo &info, const BDSMagnetStrength *scalingStrength=nullptr, const G4String &scalingKey="none")
Create a purely magnetic field.
static BDSInterpolatorType DefaultInterpolatorType(G4int numberOfDimensions)
Suggest a default interpolator.
BDSFieldObjects * CreateFieldEM(const BDSFieldInfo &info)
Create a general EM field.
BDSFieldMag * CreateFieldMagRaw(const BDSFieldInfo &info, const BDSMagnetStrength *scalingStrength=nullptr, const G4String &scalingKey="none")
Creat just the magnetic field object.
BDSFieldFactory()
Private default constructor as singleton class.
BDSModulatorInfo * GetModulatorDefinition(const G4String &modulatorName) const
BDSFieldObjects * CreateTeleporter(const BDSFieldInfo &info)
G4MagIntegratorStepper * CreateIntegratorEM(const BDSFieldInfo &info, G4EquationOfMotion *eqOfM)
static const BDSParticleDefinition * designParticle
Cache of design particle for fields.
All info required to build complete field of any type.
Definition: BDSFieldInfo.hh:66
G4String MagneticSubFieldName() const
Accessor.
void UpdateUserLimitsLengthMaximumStepSize(G4double maximumStepSize, G4bool warn=false) const
G4Transform3D TransformComplete() const
Compound transform of field + beam line transform.
G4String NameOfParserDefinition() const
Accessor.
G4bool SecondFieldOnLeft() const
Accessor.
G4double PoleTipRadius() const
Accessor.
G4bool ProvideGlobal() const
Accessor.
BDSIntegratorType IntegratorType() const
Accessor.
G4double BeamPipeRadius() const
Accessor.
G4String ElectricSubFieldName() const
Accessor.
G4Transform3D Transform() const
Transform for the field definition only.
G4bool UsePlacementWorldTransform() const
Accessor.
BDSModulatorInfo * ModulatorInfo() const
Accessor.
G4double Tilt() const
Accessor.
BDSFieldType FieldType() const
Accessor.
BDSMagnetStrength * MagnetStrength() const
Accessor.
G4double BRho() const
Accessor.
G4Transform3D TransformBeamline() const
Transform from the curvilinear coordinates to the beam line component.
BDSFieldEMInterpolated * LoadEMField(const BDSFieldInfo &info)
Main interface to load an electro-magnetic field.
BDSFieldMagInterpolated * LoadMagField(const BDSFieldInfo &info, const BDSMagnetStrength *scalingStrength=nullptr, const G4String &scalingKey="none")
Main interface to load a magnetic field.
static BDSFieldLoader * Instance()
Singleton accessor.
BDSFieldEInterpolated * LoadEField(const BDSFieldInfo &info)
Main interface to load an electric field.
Class that provides the magnetic strength in a decapole.
A perfect magetic dipole in 3D, normal field inside 1/2 poleTipRadius.
A perfect magetic dipole in 3D, normal field inside 1/2 poleTipRadius.
Class that provides the magnetic strength in a mixed dipole / quadrupole.
A uniform dipole field.
A base class for magnetic fields in local to be used in global coordinates.
A base class for magnetic fields in local to be used in global coordinates.
Two interpolated fields in one. One takes precedence in a subregion.
Class to provide scaling and a base class pointer for interpolator fields.
Sum of two multipole fields spaced by a distance in x.
Sum of two multipole fields spaced by a distance in x.
A simple paramaterisation of N-Pole outer yoke magnetic field.
A simple parameterisation of N-Pole outer yoke magnetic field.
Class that provides the magnetic strength in a quadrupole.
Field of a Muon Spoiler.
Class that provides the magnetic strength in an octupole.
Class that provides the magnetic strength in a quadrupole.
Class that provides the magnetic strength in a sextupole.
A wrapper class for BDSFieldMagSkew where it owns the field.
Class that provides the magnetic field due to a cylinder of current.
Class that provides the magnetic strength in a quadrupole.
Null B field - for special cases where we need a valid object.
Interface for static magnetic fields that may or may not be local.
Definition: BDSFieldMag.hh:39
virtual void SetTransform(const G4Transform3D &transformIn)
Definition: BDSFieldMag.cc:88
virtual G4bool TimeVarying() const
Definition: BDSFieldMag.hh:56
void SetModulator(BDSModulator *modulatorIn)
Set the optional modulator.
Definition: BDSFieldMag.hh:77
A holder for all the Geant4 field related objects.
static BDSGlobalConstants * Instance()
Access method.
Integrator for RF cavity fringes. Only the transverse momentum kicks are applied, this integrator wil...
Integrator for Decapolar field.
Derived fringe field integrator that does normalise to momentum.
Integrator that ignores the field and uses the analytical solution for a dipole kick.
Integrator for combined dipole and quadrupolar field.
Exact helix through pure dipole field.
Stepper that calculates trajectory through uniform magnetic field.
BDSIM 2nd order Euler integration.
Integrator that wraps a G4ClassicalRK4 and below a minimum step size uses a drift.
Integrator for thin h or v kick.
Integrator that ignores the field and uses the analytical solution to a multipole.
Integrator for octupole field.
Integrator that just moves the particle parallel to the s axis.
Integrator that ignores the field and uses the analytical solution to a quadrupole.
Integrator that just moves the particle parallel to the s axis.
Integrator for sextupole field.
Integrator that ignores the field and uses the analytical solution to a solenoid.
Custom unphysical integrator to advance particle in teleporter.
Override G4Mag_UsualEqRhs, provides BDSIM integrators access to particle attributes.
static const G4double beamSeparation
Used in many places - make it a constant in the code and put here as most relevant.
Efficient storage of magnet strengths.
G4bool KeyHasBeenSet(const G4String &key) const
Whether a key has been set.
static G4bool ValidKey(const G4String &key)
Whether or not the supplied key is a valid magnet strength parameter.
static const std::vector< G4String > & AllKeys()
Accessor to all keys.
static G4double Unit(const G4String &key)
Access a unit factor for a given key.
Holder class for all information required to describe a modulator.
G4double T1
Public member for direct access.
G4double frequency
Public member for direct access.
BDSModulatorType modulatorType
Public member for direct access.
G4double T0
Public member for direct access.
G4double phase
Public member for direct access.
G4double tOffset
Public member for direct access.
G4double scale
Public member for direct access.
G4double amplitudeOffset
Public member for direct access.
Sinusoidal modulator as a function of global time.
Top-hat modulator as a function of T.
Base class for a modulator.
Definition: BDSModulator.hh:37
virtual G4double RecommendedMaxStepLength() const =0
Must return the smallest spatial.
virtual G4bool VariesWithTime() const =0
Each derived class should override this.
Class to load and use PTC 1 turn map.
static BDSParser * Instance()
Access method.
Definition: BDSParser.cc:28
static bool IsInitialised()
Returns if parser is initialised.
Definition: BDSParser.cc:49
Wrapper for particle definition.
G4double BRho() const
Accessor.
Generates primary particle vertices using BDSBunch.
void RegisterPTCOneTurnMap(BDSPTCOneTurnMap *otmIn)
type underlying() const
return underlying value (can be used in switch statement)
BDSArrayReflectionTypeSet DetermineArrayReflectionTypeSet(const G4String &arrayReflectionType)
Return a std::set of reflection types. Split string on white space.
BDSInterpolatorType InterpolatorTypeSpecificFromAuto(G4int nDimension, BDSInterpolatorType autoType)
BDSModulatorType DetermineModulatorType(G4String mType)
Function that gives corresponding enum value for string (case-insensitive)
G4bool InterpolatorTypeIsAuto(BDSInterpolatorType typeIn)
Return true if the type is one containing 'auto'.
BDSFieldFormat DetermineFieldFormat(G4String fieldformat)
Function that gives corresponding enum value for string (case-insensitive)
std::pair< G4String, G4String > SplitOnColon(const G4String &formatAndPath)
BDSFieldType DetermineFieldType(G4String fieldType)
Function that gives corresponding enum value for string (case-insensitive)
Definition: BDSFieldType.cc:90
BDSInterpolatorType DetermineInterpolatorType(G4String interpolatorType)
Function that determines enum from string (case-insensitive).
BDSFieldClassType DetermineFieldClassType(BDSFieldType fieldType)
Function that gives the corresponding enum value for a field type enum.
G4String GetFullPath(G4String filename, bool excludeNameFromPath=false, bool useCWDForPrefix=false)
G4UserLimits * CreateUserLimits(G4UserLimits *defaultUL, G4double length, G4double fraction=1.6)
BDSIntegratorType DetermineIntegratorType(G4String integratorType)
Function that determines enum from string (case-insensitive).
G4bool IsFinite(G4double value, G4double tolerance=std::numeric_limits< double >::epsilon())
G4int NDimensionsOfInterpolatorType(const BDSInterpolatorType &it)
Report the number of dimensions for that interpolator type.
G4int NDimensionsOfFieldFormat(const BDSFieldFormat &ff)
Report the number of dimensions for that format.
std::map< G4String, G4String > GetUserParametersMap(const G4String &userParameters, char delimiter=':')
Take one long string and split on space and then on colon. "key1:value1 key2:value2" etc.