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()
.