In my code, I need to be able to implement 2 separate local field managers that both have two different uniform electric fields. In order to do this, I’ve made two unique field managers in my field setup code. I then used this FieldSetup in my ConstructSDandField() method in the DetectorConstruction code.
Now, for some reason, when I try to “make” my program, it responds with the following error :
CMakeFiles/BckgrdReduct.dir/src/BckgrdReductDetectorConstruction.cc.o:BckgrdReductDetectorConstruction.cc:function BckgrdReductDetectorConstruction::ConstructSDandField(): error: undefined reference to 'BckgrdReductFieldSetup::BckgrdReductFieldSetup()'
CMakeFiles/BckgrdReduct.dir/src/BckgrdReductDetectorConstruction.cc.o:BckgrdReductDetectorConstruction.cc:function BckgrdReductDetectorConstruction::ConstructSDandField(): error: undefined reference to 'void G4AutoDelete::Register<BckgrdReductFieldSetup>(BckgrdReductFieldSetup*)'
collect2: error: ld returned 1 exit status
make[2]: *** [BckgrdReduct] Error 1
make[1]: *** [CMakeFiles/BckgrdReduct.dir/all] Error 2
make: *** [all] Error 2
Here is my header file for my FieldSetup
#ifndef BckgrdReductFieldSetup_h
#define BckgrdReductFieldSetup_h 1
#include "G4ElectricField.hh"
#include "G4UniformElectricField.hh"
class G4FieldManager;
class G4ChordFinder;
class G4EquationOfMotion;
class G4Mag_EqRhs;
class G4EqMagElectricField;
class G4MagIntegratorStepper;
class G4MagInt_Driver;
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
class BckgrdReductFieldSetup
{
public:
BckgrdReductFieldSetup();
virtual ~BckgrdReductFieldSetup();
void SetStepperType(G4int i) { fStepperType = i; CreateSteppers(); }
void SetMinStep(G4double s) {fMinStep = s;}
void SetDriftFieldValue(G4ThreeVector fieldVector);
void SetDriftFieldZValue(G4double fieldValue);
G4ThreeVector GetDriftFieldValue() const { return GetConstantFieldValue(fDriftElectricField);}
void SetTransferFieldValue(G4ThreeVector fieldVector);
void SetTransferFieldZValue(G4double fieldValue);
G4ThreeVector GetTransferFieldValue() const { return GetConstantFieldValue(fTransferElectricField);}
G4FieldManager* GetDriftFieldManager() { return fDriftFieldManager;}
G4FieldManager* GetTransferFieldManager() { return fTransferFieldManager;}
G4ThreeVector GetConstantFieldValue(G4ElectricField* electricField) const;
void UpdateIntegrator();
protected:
void CreateSteppers();
private:
G4FieldManager* fDriftFieldManager;
G4FieldManager* fTransferFieldManager;
G4ChordFinder* fDriftChordFinder;
G4ChordFinder* fTransferChordFinder;
G4EqMagElectricField* fDriftEquation;
G4EqMagElectricField* fTransferEquation;
G4UniformElectricField* fDriftElectricField;
G4UniformElectricField* fTransferElectricField;
G4MagIntegratorStepper* fDriftStepper;
G4MagIntegratorStepper* fTransferStepper;
G4MagInt_Driver* fDriftIntgrDriver;
G4MagInt_Driver* fTransferIntgrDriver;
G4int fStepperType;
G4double fMinStep;
};
#endif
Here is the FieldSetup.cc file
#include "BckgrdReductFieldSetup.hh"
#include "G4UniformElectricField.hh"
#include "G4UniformMagField.hh"
#include "G4MagneticField.hh"
#include "G4FieldManager.hh"
#include "G4TransportationManager.hh"
#include "G4EquationOfMotion.hh"
#include "G4EqMagElectricField.hh"
#include "G4Mag_UsualEqRhs.hh"
#include "G4MagIntegratorStepper.hh"
#include "G4MagIntegratorDriver.hh"
#include "G4ChordFinder.hh"
#include "G4ExplicitEuler.hh"
#include "G4ImplicitEuler.hh"
#include "G4SimpleRunge.hh"
#include "G4SimpleHeum.hh"
#include "G4ClassicalRK4.hh"
#include "G4HelixExplicitEuler.hh"
#include "G4HelixImplicitEuler.hh"
#include "G4HelixSimpleRunge.hh"
#include "G4CashKarpRKF45.hh"
#include "G4RKG3_Stepper.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
BckgrdReductFieldSetup::BckgrdReductFieldSetup()
{
fDriftElectricField = new G4UniformElectricField(G4ThreeVector(0.0,
0.0,
211000 * volt/m));
fTransferElectricField = new G4UniformElectricField(G4ThreeVector(0.0,
0.0,
317000 * volt/m));
fDriftEquation = new G4EqMagElectricField(fDriftElectricField);
fTransferEquation = new G4EqMagElectricField(fTransferElectricField);
fDriftFieldManager = new G4FieldManager();
fTransferFieldManager = new G4FieldManager();
fMinStep = 0.01 * mm;
fStepperType = ;
UpdateIntegrator();
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
BckgrdReductFieldSetup::~BckgrdReductFieldSetup()
{
delete fDriftElectricField; fDriftElectricField = nullptr;
delete fTransferElectricField; fTransferElectricField = nullptr;
///////////////////////////////////////////
delete fDriftChordFinder; fDriftChordFinder = nullptr;
delete fTransferChordFinder; fTransferChordFinder = nullptr;
////////////////////////////////////////
delete fDriftStepper; fDriftStepper = nullptr;
delete fTransferStepper; fTransferStepper = nullptr;
/////////////////////////////////////////////
delete fDriftEquation; fDriftEquation = nullptr;
delete fTransferEquation; fTransferEquation = nullptr;
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void BckgrdReductFieldSetup::UpdateIntegrator()
{
// Create Stepper and Chord Finder with predefined type, minstep (resp.)
// It must be possible to call 'again' after an alternative stepper
// has been chosen, or other changes have been made
assert(fDriftEquation != nullptr);
assert(fTransferEquation != nullptr);
G4cout << "BckgrdReductFieldSetup: The minimal step is equal to "
<< fMinStep/mm << " mm" << G4endl;
if (fDriftChordFinder) {
delete fDriftChordFinder;
fDriftChordFinder = nullptr;
// The Chord-finder's destructor deletes the driver
fDriftIntgrDriver = nullptr;
}
if (fTransferChordFinder) {
delete fTransferChordFinder;
fTransferChordFinder = nullptr;
// The Chord-finder's destructor deletes the driver
fTransferIntgrDriver = nullptr;
}
// Currently both drivers does not 'own' stepper
// -- so this stepper is still a valid object after this
if (fDriftStepper) {
delete fDriftStepper;
fDriftStepper = nullptr;
}
if (fTransferStepper) {
delete fTransferStepper;
fTransferStepper = nullptr;
}
// Create the new objects, in turn for all relevant classes
// -- Careful to call this after all old objects are destroyed, and
// pointers nullified.
CreateStepper(); // Note that this methode deleted the existing Stepper!
assert(fDriftStepper != nullptr);
assert(fTransferStepper != nullptr);
if (fDriftStepper) {
fDriftIntgrDriver = new G4MagInt_Driver(fMinStep,
fDriftStepper,
fDriftStepper->GetNumberOfVariables());
if (fDriftIntgrDriver) {
fDriftChordFinder = new G4ChordFinder(fDriftIntgrDriver);
}
}
if (fTransferStepper) {
fTransferIntgrDriver = new G4MagInt_Driver(fMinStep,
fTransferStepper,
fTransferStepper->GetNumberOfVariables());
if (fTransferIntgrDriver) {
fTransferChordFinder = new G4ChordFinder(fTransferIntgrDriver);
}
}
fDriftFieldManager->SetChordFinder(fDriftChordFinder);
fTransferFieldManager->SetChordFinder(fTransferChordFinder);
fDriftFieldManager->SetDetectorField(fDriftElectricField);
fTransferFieldManager->SetDetectorField(fTransferElectricField);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void BckgrdReductFieldSetup::CreateSteppers()
{
// Deletes the existing stepper
// and creates a new stepper object of the chosen stepper type
const G4int nvar = 8;
auto oldStepper= fStepper;
switch ( fStepperType )
{
case 0:
fDriftStepper = new G4ExplicitEuler( fDriftEquation, nvar );
fTransferStepper = new G4ExplicitEuler(fTransferEquation, nvar);
G4cout<<"G4ExplicitEuler is calledS"<<G4endl;
break;
case 1:
fDriftStepper = new G4ImplicitEuler( fDriftEquation, nvar );
fTransferStepper = new G4ImplicitEuler(fTransferEquation, nvar);
G4cout<<"G4ImplicitEuler is called"<<G4endl;
break;
case 2:
fDriftStepper = new G4SimpleRunge( fDriftEquation, nvar );
fTransferStepper = new G4SimpleRunge(fTransferEquation, nvar);
G4cout<<"G4SimpleRunge is called"<<G4endl;
break;
case 3:
fDriftStepper = new G4SimpleHeum( fDriftEquation, nvar );
fTransferStepper = new S4SimpleHeum(fTransferEquation, nvar);
G4cout<<"G4SimpleHeum is called"<<G4endl;
break;
case 4:
fDriftStepper = new G4ClassicalRK4( fDriftEquation, nvar );
fTransferStepper = new G4ClassicalRK4( fTransferEquation, nvar);
G4cout<<"G4ClassicalRK4 is called"<<G4endl;
break;
case 5:
fDriftStepper = new G4CashKarpRKF45( fDriftEquation, nvar );
fTransferStepper = new G4CashKarpRKF45(fTransferEquation, nvar);
G4cout<<"G4CashKarpRKF45 is called"<<G4endl;
break;
case 6:
fStepper = 0; // new G4RKG3_Stepper( fEquation, nvar );
G4cout<<"G4RKG3_Stepper is not currently working for Electric Field"
<<G4endl;
break;
case 7:
fStepper = 0; // new G4HelixExplicitEuler( fEquation );
G4cout<<"G4HelixExplicitEuler is not valid for Electric Field"<<G4endl;
break;
case 8:
fStepper = 0; // new G4HelixImplicitEuler( fEquation );
G4cout<<"G4HelixImplicitEuler is not valid for Electric Field"<<G4endl;
break;
case 9:
fStepper = 0; // new G4HelixSimpleRunge( fEquation );
G4cout<<"G4HelixSimpleRunge is not valid for Electric Field"<<G4endl;
break;
default: /* fStepper = 0; // Older code */
fDriftStepper = new G4ClassicalRK4( fDriftEquation, nvar );
fTransferStepper = new G4ClassicalRK4( fTransferEquation, nvar);
G4cout<<"G4ClassicalRK4 (default) is called"<<G4endl;
break;
}
delete oldStepper;
// Now must make sure it is 'stripped' from the dependent object(s)
// ... but the next line does this anyway - by informing
// the driver (if it exists) about the new stepper.
// Always inform the (existing) driver about the new stepper
if( fDriftIntgrDriver )
fDriftIntgrDriver->RenewStepperAndAdjust( fDriftStepper );
if (fTransferIntgrDriver)
fTransferIntgrDriver->RenewStepperAndAdjust(fTransferStepper);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void BckgrdReductFieldSetup::SetDriftFieldZValue(G4double fieldStrength)
{
G4ThreeVector fieldSetVec(0.0, 0.0, fieldStrength);
SetDriftFieldValue(fieldSetVec);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void BckgrdReductFieldSetup::SetDriftFieldZValue(G4double fieldStrength)
{
G4ThreeVector fieldSetVec(0.0, 0.0, fieldStrength);
SetTransferFieldValue(fieldSetVec);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void BckgrdReductFieldSetup::SetDriftFieldValue(G4ThreeVector fieldVector)
{
if(fDriftElectricField) delete fDriftElectricField;
if (fieldVector != G4ThreeVector(0., 0., 0.))
{
fDriftElectricField = new G4UniformElectricField(fieldVector);
}
else
{
// If the new field's value is Zero, then
// setting the pointer to zero ensures
// that it is not used for propagation.
fDriftElectricField = 0;
}
// Either
// - UpdateField() to reset all (ChordFinder, Equation);
// UpdateField();
// or simply update the field manager & equation of motion
// with pointer to new field
GetDriftFieldManager()->SetDetectorField(fDriftElectricField);
fDriftEquation->SetFieldObj(fDriftElectricField);
}
//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void BckgrdReductFieldSetup::SetTransferFieldValue(G4ThreeVector fieldVector)
{
if(fTransferElectricField) delete fTransferElectricField;
if (fieldVector != G4ThreeVector(0., 0., 0.))
{
fTransferElectricField = new G4UniformElectricField(fieldVector);
}
else
{
// If the new field's value is Zero, then
// setting the pointer to zero ensures
// that it is not used for propagation.
fTransferElectricField = 0;
}
// Either
// - UpdateField() to reset all (ChordFinder, Equation);
// UpdateField();
// or simply update the field manager & equation of motion
// with pointer to new field
GetTransferFieldManager()->SetDetectorField(fTransferElectricField);
fTransferEquation->SetFieldObj(fTransferElectricField);
}
G4ThreeVector BckgrdReductFieldSetup::GetConstantFieldValue(G4ElectricField* electricField) const
{
if (!electricField) return G4ThreeVector();
static G4double fieldValue[6], position[4];
position[0] = position[1] = position[2] = position[3] = 0.0;
electricField->GetFieldValue(position, fieldValue);
G4ThreeVector fieldVec(fieldValue[3], fieldValue[4], fieldValue[5]);
return fieldVec;
}
And here is my ConstructSDandField method:
void BckgrdReductDetectorConstruction::ConstructSDandField()
{
// Construct field creator - register the field it creates
if (!fEMFieldSetup.Get()) {
BckgrdReductFieldSetup* emFieldSetup = new BckgrdReductFieldSetup();
G4AutoDelete::Register(emFieldSetup);
fEMFieldSetup.Put(emFieldSetup);
}
G4bool allLocal = true;
logicScoring->SetFieldManager(fEMFieldSetup.Get()->GetDriftFieldManager(), allLocal);
logicSmall_GEMGas_Layer->SetFieldManager(fEMFieldSetup.Get()->GetTransferFieldManager(), allLocal);
if (fOrientation == "up" || fOrientation == "Up" || fOrientation == "Upstream" || fOrientation == "upstream"|| fOrientation == "front" || fOrientation == "Front") {
logicKap_Layer->SetFieldManager(fEMFieldSetup.Get()->GetDriftFieldManager(), allLocal);
}
}
I don’t really understand why this is not working. I’ve been double and triple checking my constructors and I can’t see anything obviously wrong. If someone could suggest a solution and help me out, that would be much appreciated. Thank you so much.