Sınıfta Petsc Mat nesnesi
[Petsc için nispeten yeni] Nesne yönelimli bir proje yazıyorum ve benim fikrim, kullanıcı nesneyi MPI argümanlarıyla oluşturduğunda paralel nesnelere sahip olmaktır. Öyleyse üye verileri Mat'a sahip olun ve kurucuda doldurun / birleştirin. Bunu doğru bir şekilde yapmakta zorlanmama rağmen, bu benim ilk sorum (kodun altına bakın. Hata ayıklamak için asgari bir çalışma örneğine ihtiyacınız varsa lütfen bana bildirin). İkinci genel sorum, bunu nasıl yapacaksın? Kapsüllemeyi bozmadan ve genel iyi uygulamalara sahip olmadan bu nesne ile nasıl arayüz oluşturursunuz?
İşte düşündüğüm şeyin bir örneği, önce hpp dosyası
class Toperator {
public:
/// Toperator: $T = \Del^2 + \frac{l(l+1)}{2x^2}$
Toperator(std::shared_ptr<FEMDVR> a_radial_grid, const int &a_lmax_times_2);
Toperator(const PetscMPIInt &a_numprocs, const PetscMPIInt &id,
std::shared_ptr<FEMDVR> a_radial_grid, const int &a_lmax_times_2);
/// Destructor
~Toperator();
/// Needed to destroy the TXX Petsc Matrix
void destroyTXXPetscMatrix();
/// Needed to destroy the TIXX Petsc Matrix
void destroyTIXXPetscMatrix();
/// Returns the TXX Petsc Matrix, i.e. return type Mat
Mat getTXXPetscMat();
/// Returns the TIXX Petsc Matrix, i.e. return type Mat
Mat getTIXXPetscMat();
/// Getter for the T operator in the DVR representation.
std::complex<double> getTXX(int index) const;
/// Getter for the inverse of the T operator in the DVR representation.
/// Used in the poison solution for $\frac{1}{|r_1-r_2|}.
std::complex<double> getTIXX(int index) const;
private:
std::unique_ptr<std::complex<double>[]> m_dvr_rep, m_inverse_dvr_rep;
Mat m_TXX, m_TIXX;
};
Unutulmaması gereken bir şey, Petsc Mat nesnelerini yok eden ancak bunu nasıl yapacağımı bilmeyen özel bir yıkıcı oluşturmak istiyorum. Genel olarak, bir sınıfta bu Mat nesnesiyle nasıl arayüz oluşturursunuz? Sadece tüm Mat'ı iade ediyorum ama bunun işe yarayıp yaramadığından emin değilim. Yine de, daha iyi tasarımlar duymak isterim!
Şimdi paralel kurucu uygulaması (Üye listesinde Mat'ın başlatılmasından emin değilim).
Toperator::Toperator(const PetscMPIInt &a_numprocs, const PetscMPIInt &id,
std::shared_ptr<FEMDVR> a_radial_grid,
const int &a_lmax_times_2)
: m_dvr_rep(std::unique_ptr<std::complex<double>[]>(
new std::complex<double>[a_radial_grid->getNbas() *
a_radial_grid->getNbas() *
a_lmax_times_2]())),
m_inverse_dvr_rep(std::unique_ptr<std::complex<double>[]>(
new std::complex<double>[a_radial_grid->getNbas() *
a_radial_grid->getNbas() *
a_lmax_times_2]())), m_TXX(nullptr), m_TIXX(nullptr) {
PetscErrorCode ierr;
PetscInt nbas = a_radial_grid->getNbas();
ierr = MatCreate(PETSC_COMM_WORLD, &m_TXX);
ierr = MatSetSizes(m_TXX, PETSC_DECIDE, PETSC_DECIDE, a_lmax_times_2,
nbas * nbas);
ierr = MatSetFromOptions(m_TXX);
ierr = MatSetUp(m_TXX);
int start, end;
MatGetOwnershipRange(m_TXX, &start, &end);
for (int l = start; l < end; ++l) {
for (int i = 0; i < nbas; ++i) {
for (int j = 0; j < nbas; ++j) {
if (i == j) {
int index = i * nbas + j;
PetscScalar tmp_TXX = a_radial_grid->getLaplacian(i * nbas + j) +
(std::complex<double>)(l * (l + 1)) /
pow(a_radial_grid->getPoint(j), 2);
/* MatSetValue(m_TXX, l, index, tmp_TXX, ADD_VALUES); */
MatSetValues(m_TXX, 1, &l, 1, &index, &tmp_TXX, INSERT_VALUES);
} else {
int index = i * nbas + j;
PetscScalar tmp_TXX = a_radial_grid->getLaplacian(i * nbas + j);
/* MatSetValue(m_TXX, l, index, tmp_TXX, ADD_VALUES); */
MatSetValues(m_TXX, 1, &l, 1, &index, &tmp_TXX, INSERT_VALUES);
}
}
}
}
MatAssemblyBegin(m_TXX, MAT_FINAL_ASSEMBLY);
MatAssemblyEnd(m_TXX, MAT_FINAL_ASSEMBLY);
}
Toperator::~Toperator() {}
void Toperator::destroyTXXPetscMatrix() { MatDestroy(&m_TXX); }
void Toperator::destroyTIXXPetscMatrix() { MatDestroy(&m_TIXX); }
Mat Toperator::getTXXPetscMat() { return m_TXX; }
Mat Toperator::getTIXXPetscMat() { return m_TIXX; }
std::complex<double> Toperator::getTXX(int index) const {
return m_dvr_rep[index];
}
std::complex<double> Toperator::getTIXX(int index) const {
return m_inverse_dvr_rep[index];
}
MatSetValues düzgün çalışmıyor. İşte çıktı. Laplacian değerlerim değil, sadece yinelemeler gibi görünüyor.
local_row 19 local_column 8
Mat Object: 2 MPI processes
type: mpiaij
row 0: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 1: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 2: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 3: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 4: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 5: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 6: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 7: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 8: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 9: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 10: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 11: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 12: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 13: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 14: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 15: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 16: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 17: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
row 18: (0, 1.) (1, 0.) (2, 0.) (3, 0.) (4, 0.) (5, 0.) (6, 0.) (7, 0.)
İşte sıralı çalışma kodu
int nbas = a_radial_grid->getNbas();
for (int l = 0; l < a_lmax_times_2; ++l) {
for (int i = 0; i < nbas; ++i) {
for (int j = 0; j < nbas; ++j) {
if (i == j) {
m_dvr_rep[l * nbas * nbas + i * nbas + j] =
a_radial_grid->getLaplacian(i * nbas + j) +
(std::complex<double>)(l * (l + 1)) /
pow(a_radial_grid->getPoint(j), 2);
} else {
m_dvr_rep[l * nbas * nbas + i * nbas + j] =
a_radial_grid->getLaplacian(i * nbas + j);
}
}
}
}
Bu kod parçacığında m_dvr_rep, Paralelde oluşturmaya çalıştığım Petsc Mat'tır. Gördüğünüz gibi, üç döngü boyunca ilerliyorum, bu yüzden bu yapıyı Mat ile nasıl eşleştireceğimi bilmiyorum ama yukarıdaki girişimimi görebilirsiniz. Matrix'e baktığımda sadece yinelemeleri var, bu yüzden aptalca bir şey yaptığımı düşünüyorum.
Yanıtlar
Bir örnek arıyorsanız, buradaki MatrixBasesınıfa bir göz atın :https://github.com/dealii/dealii/blob/master/include/deal.II/lac/petsc_matrix_base.h https://github.com/dealii/dealii/blob/master/source/lac/petsc_matrix_base.cc
- MatDestroy'u yok edicinize koyun.
- Öğeleri ayarlama mantığınız tamamen yanlış. En kolay çözüm şudur:
// şey
for ( .... i .... )
for ( ... j ... )
for ( .... l ... )
globalnumber = l * nbas * nbas + i * nbas + j
if ( globalnumber>=low && globalnumber<high )
MatSetValue