Undefined Reference to FieldSetup constructor

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.

All I think of is that the FieldSetup.cc file isn’t being included in the build - could you post your CMakeLists.txt script?

Just had to do cmake command in terminal instead of just “make” and it worked. I think it was just not linking all of the files , including FieldSetup.cc, and not seeing it.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.