No worries, I posted late on Friday, I was expecting it would take a few days to get back to me.
Thanks a lot for offering to help!
Essentially, I was setting up a scaffolding that looks like:
#include <map>
#include <string>
#include "G4Material.hh"
#include "json.hpp"
class MaterialDatabase {
public:
explicit MaterialDatabase(nlohmann::json const& config);
private:
G4Isotope parseIsotope(std::string name, nlohmann::json const& iso);
G4Element parseElement(std::string name, nlohmann::json const& el);
G4Material parseMaterial(std::string name, nlohmann::json const& mat);
std::map<std::string, G4Material> m_materials;
std::map<std::string, G4Element> m_elements;
std::map<std::string, G4Isotope> m_isotopes;
};
G4Isotope MaterialDatabase::parseIsotope(std::string name, nlohmann::json const& iso) {
return G4Isotope(
name, // name
iso.at("Z").get<G4int>(), // atomic number
iso.at("A").get<G4int>(), // number of nucleons
iso.at("a").get<G4double>(), // mass of mole
0 // isomer level
);
}
G4Element MaterialDatabase::parseElement(std::string name, nlohmann::json const& el) {
return G4Element(
name, // name
el.at("symbol").get<std::string>(), // symbol
el.at("Z").get<G4double>(), // atomic number
el.at("a").get<G4double>() // mass of mole
);
}
G4Material MaterialDatabase::parseMaterial(std::string name, nlohmann::json const& mat) {
auto components = mat.at("components").get<std::map<std::string, int>>();
G4Material res = G4Material(
name, // name
1, // density (faked at this stage)
components.size()
);
for (auto [k, v] : components) {
res.AddElement(m_elements.at(k), v);
}
return res;
}
MaterialDatabase::MaterialDatabase(nlohmann::json const& config) {
auto isotopes = config.at("isotopes");
for (auto [k, v] : isotopes.items()) {
m_isotopes[k] = parseIsotope(k, v);
}
auto elements = config.at("elements");
for (auto [k, v] : elements.items()) {
m_elements[k] = parseElement(k, v);
}
auto materials = config.at("materials");
for (auto [k, v] : materials.items()) {
m_materials[k] = parseMaterial(k, v);
}
}
In order to pull in material definitions from json files in preparation for mixing them, when I originally ran into the errors about the copy ctor being deleted. This is easy enough to fix.
Now, I am a Geant beginner, but I’ve had quite a bit of C++ experience, so I didn’t realize that this was duplicating effort with Geant at the time I wrote it (I figured it out prior to writing the original post), which maintains its own database of materials automagically. So the parts of this class that store the data in a hashmap have been removed, and everything just returns pointers now. But that raised a new question: how can I prevent unbounded linear growth in the size of the internally maintained Geant Materials Table? I don’t have access to it, so I can’t change or remove items from it, or force it to compact indices or reuse freed ones.
Specifically, if I were to just generate (for instance) 1,000,000 materials for 1,000,000 cells in the ground, then free them, then do it again, and so on (following code untested):
// generate a randomized material
G4Material* makeRandMat(int i, int j, int k, int seed) {
// uses x, y, and z, along with the previously read data from the json using a noising algorithm
// simply stubbed out here, it will have the name "voxel-mat-i-j-k"
return G4NistManager::Instance()->FindOrBuildMaterial("G4_AIR");
}
void populateWorld(G4LogicalVolume *voxel_arena, int seed) {
G4double voxel_size = 1*cm;
bool checkOverlaps = true;
for (int i=0; i < 100; ++i) {
for (int j=0; j < 100; ++j) {
for (int k=0; k < 100; ++k) {
auto voxel = new G4Box(std:format("voxel-{}-{}-{}", i, j, k), voxel_size, voxel_size, voxel_size);
auto voxel_logic = new G4LogicalVolume(voxel, makeRandMat(i, j, k, seed), std::format("voxel-logic-{}-{}-{}", i, j, k));
auto voxel_placement = new G4VPlacement(nullptr, G4ThreeVector(i*cm, j*cm, k*cm), voxel_logic, std::format("voxel-place-{}-{}-{}", i, j, k), voxel_arena, false, 0, checkOverlaps);
}
}
}
}
// later on we can delete all of these materials and voxels and so on, if we choose,
// but if we intend to run this 100 times to generate 100 different material configurations
// then we use 100 times the memory in this list. It's akin to memory leak.
void clearMaterials() {
for (int i=0; i < 100; ++i) {
for (int j=0; j < 100; ++j) {
for (int k=0; k < 100; ++k) {
G4Material *matptr = G4Material::GetMaterial(std::format("voxel-mat-{}-{}-{}", i, j, k), false));
delete matptr; // Frees memory, but not the `theMaterialTable` entry
}
}
}
}