How can I use G4PhysicsTable::insertAt()?

I’m making my own physics process, and implementing MyProcess::BuildPhysicsTable(). I wrote it like G4OpRayleigh::BuildPhysicsTable(), but it causes EXC_BAD_ACCESS at G4PhysicsTable::insertAt().

I also wrote as a comparison as follows, and this crashes at insertAt(), too:

#include "B1DetectorConstruction.hh"
#include "B1ActionInitialization.hh"
#include "G4RunManager.hh"
#include "G4PhysicsTable.hh"
#include "G4PhysicsOrderedFreeVector.hh"
int main(int argc,char** argv)
{
  auto physics_table_ = new G4PhysicsTable(10);
  auto v = new G4PhysicsOrderedFreeVector();
  physics_table_->insertAt(4, v);
  delete physics_table_;
  delete v;
  // following is same as examples/basic/B1...
}

Why does this crash? Is it not recommended to use G4PhysicsTable::insertAt() like this?

According to $G4INCLUDE/G4PhysicsTable.hh, the G4PhysicsTable object is a subclass of std::vector<>. I just checked global/management/src/G4PhysicsTable.cc, and the size-based constructor uses std::vector::reserve(), not ...::resize(). Consequently, although a chunk of memory is “blocked out” for 10 elements (in your example), the vector itself is still empty.

G4PhysicsTable::insertAt() is implemented as

G4PhysicsTableIterator itr=begin();
for (size_t i=0; i<idx; ++i) { itr++; }
G4PhysCollection::insert(itr, pvec);

with no checking on overrun. So, when you attempt to do insertAt() on an empty vector, the itr value points beyond the end of the vector, and the system is quite unhappy.

This might even be worth a bug report: I think that code should pre-test for idx < entries(), and either fail out with an error, or default to “insert at end”.

Thank you! I’ve made a bug report. Now I use G4PhysicsTable::insertAt() as follows:

auto physics_table_ = new G4PhysicsTable();
physics_table_->resize(10);
auto v = new G4PhysicsOrderedFreeVector();
physics_table_->insertAt(4, v);
delete physics_table_;
delete v;

It works!

Could you please explain why you have to start with idx=4 rather than 0? We naively assumed insertAt() to be invoked in the sequential order. If there is a strong use-case of random ordering, we will change the code to address it. But otherwise, we will admit this fraud and protect insertAt() against idx > entries().
Please note that, when you insert a vector as the 5th entry (idx=4), 1st through 4th entries might be uninitialized (or initialized to null). Thus we always have to check if access to the PhysicsTable with such indices is legitimate. Given so frequent use of this class objects, we’d like to avoid any unnecessary checks that might affect on the performance.

@asaim Thank you for your detailed explanation, I misunderstood the usage of insertAt() in some way.
Your assumption is reasonable for the usage of PhysicsTable. As a matter of fact I don’t necessarily have to make physics tables in random ordering, I changed my code after reading your comment. You can close the report anytime as you like. Thank you for your time and effort!

Thanks for your clarification. We will protect insertAt() against idx > entries() and your Bugzilla report will be updated accordingly.

The fix is already integrated to the development version and will be publicly avaible in the next Geant4 version in December. In a mean time, take care about table length when insert a new vector. The problem is solved.