I want to create a struct-of-arrays (SOA) database for better cache use but also have a separate interface that gives encapsulation. I am close to the design I think but would like more experienced coding eyes to have a look to critique my design. Here is what I have so far:
struct OrbitalDataBase {
OrbitalDataBase(std::shared_ptr<FEMDVR> a_radial_grid, std::shared_ptr<AngularGrid> a_angular_grid)
: nbas(a_radial_grid->getNbas()), number_of_lm_pairs_per_orbital(), m_orbital_coefs() {
m_orbitals_coefs.reserve(a_radial_grid->getNbas() * a_angular_grid->getNumChannels());
}
inline void StoreData(const uint32_t &a_ith_orbital,
std::shared_ptr<MOPartialWaveRepresentation> a_MO) {
this->number_of_lm_pairs_per_orbital.push_back(a_MO->getNumChannels());
this->m_orbital_coefs.reserve(a_ith_orbital * nbas *
a_MO->getNumChannels());
for (uint32_t i = 0; i < nbas * a_MO->getNumChannels();
++i) {
this->m_orbital_coefs.push_back(a_MO->getPartialWaveRep(i));
}
}
/* private: */
uint32_t nbas;
std::vector<uint32_t> number_of_lm_pairs_per_orbital;
std::vector<std::complex<double>> m_orbital_coefs;
};
struct OrbitalAccessor {
OrbitalAccessor(const OrbitalDataBase &a_orbital_data)
: orbital_data(a_orbital_data){};
inline std::complex<double> coef(uint32_t ith_orbital, uint32_t i) const {
return this->orbital_data.m_orbital_coefs
[ith_orbital * this->orbital_data.nbas *
this->orbital_data.number_of_lm_pairs_per_orbital[ith_orbital] +
i];
}
private:
const OrbitalDataBase orbital_data;
};
How this would work is construct the database with the number of orbitals and then in a for-loop, save all the ith_orbital's coefficients in one large array. Something like this
uint32_t number_of_orbitals = 5;
OrbitalDataBase orb_data_base(number_of_orbitals);
for (uint32_t ith_orbital = 0; ith_orbital < number_of_orbitals < ++ith_orbital)
{
Orbital();
orb_data_base.StoreData(ith_orbital, femdvr_grid, orbital);
}
The Orbital()
function just creates the orbital I want to store. Then the OrbitalAccessor
should be able to access these large arrays index with stride ith_orbital
. I think I should pass the accessor the created database I want to access in a constructor like
int which_orbital = 1, int index 4; // example looks at 2nd orbital's 5th coefficient
OrbitalAccessor orb_accessor(orb_data_base);
orb_accessor.coef(which_orbital, index);
I tried to have the ObitalDataBase member data private
but I get
'm_orbitals_coefs' is a private member of 'OrbitalDataBase'
so I commented the private:
keyword so it will compile. I think they should be private for encapsulation so I'd prefer that if I am correct.
I think a better way would be to have OrbitalAccessor
derive the OrbitalDataBase
rather than pass it in to a constructor.
UPDATE: I changed the code a little so now the m_orbital_coef
has a base vector capacity and resizes if it becomes larger because a_MO->getNumChannels()
can be larger than a_angular_grid->getNumChannels()
.