代码拉取完成,页面将自动刷新
#include "wrapper_sstructmg.h"
const idx_t num_diag = 7;
int main(int argc, char* argv[])
{
int my_pid, num_procs;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &my_pid);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
idx_t arg_cnt = 1;
const idx_t local_m = atoi(argv[arg_cnt++]),// 每个part内有一个box,该box有m*m*m个cell
np_per_dim = atoi(argv[arg_cnt++]),// 每个part内有一个box,该box有p*p*p个进程组成
glb_nparts = 2;
const std::string its_name = std::string(argv[arg_cnt++]),
prc_name = std::string(argv[arg_cnt++]);
std::string config_mg_file;
if (prc_name == "GMG") config_mg_file = std::string(argv[arg_cnt++]);
const idx_t ncells_per_dim = local_m * np_per_dim,
ncells_per_part = ncells_per_dim * ncells_per_dim * ncells_per_dim,
nprocs_per_part = np_per_dim * np_per_dim * np_per_dim;
assert(ncells_per_dim % 4 == 0);
assert(num_procs == nprocs_per_part * glb_nparts);
const idx_t my_part = my_pid / nprocs_per_part,
pid_in_part = my_pid - my_part * nprocs_per_part;
idx_t cart_ids[3];
{// 计算本进程在part内处于什么位置
cart_ids[0] = pid_in_part / (np_per_dim * np_per_dim);
cart_ids[1] = (pid_in_part - cart_ids[0] * np_per_dim * np_per_dim) / np_per_dim;
cart_ids[2] = (pid_in_part - cart_ids[0] * np_per_dim * np_per_dim - cart_ids[1] * np_per_dim);
}
idx_t my_ilower[3], my_iupper[3], box_ends[3];
idx_t my_nelems = 1;
for (idx_t d = 0; d < 3; d++) {
my_ilower[d] = cart_ids[d] * local_m;
my_iupper[d] = (cart_ids[d] + 1)* local_m - 1;
box_ends[d] = my_iupper[d] + 1;
my_nelems *= (my_iupper[d] - my_ilower[d] + 1);
}
#if LOAD_REBAL
#endif
#ifdef DEBUG_PRINT
for (int p = 0; p < num_procs; p++) {
if (my_pid == p) {
printf("Proc %d part %d: (%d,%d,%d)~(%d,%d,%d)\n", my_pid, my_part,
my_ilower[0], my_ilower[1], my_ilower[2],
my_iupper[0], my_iupper[1], my_iupper[2] );
fflush(stdout);
}
MPI_Barrier(MPI_COMM_WORLD);
}
MPI_Barrier(MPI_COMM_WORLD);
#endif
if (my_pid == 0) {
printf("\033[1;35m Local M = %d P: %d Total #procs: %d Total #dof: %d \033[0m \n",
local_m, np_per_dim, num_procs, ncells_per_part * glb_nparts);
}
SStructMG_Init();
{
SStructGrid<idx_t> ssgrid(MPI_COMM_WORLD, 3, glb_nparts);
const idx_t halos[3] = {1, 1, 1};
{// 添加本进程所拥有的块和盒子
const idx_t blk_exts[3] = { ncells_per_dim, ncells_per_dim, ncells_per_dim };
const bool periods[3] = {false, false, false};
ssgrid.addBlock(my_part, blk_exts, periods);
ssgrid.addBox(my_part, my_ilower, box_ends);
}
ssgrid.assemble();
const idx_t my_nblks = ssgrid.my_blk_list.size(); assert(my_nblks == 1);
idx_t shalos[my_nblks * 3];
for (idx_t k = 0; k < my_nblks; k++) {
shalos[k * 3 + 0] = halos[0];
shalos[k * 3 + 1] = halos[1];
shalos[k * 3 + 2] = halos[2];
}
// 根据半结构网格建立向量
par_SstructVector<idx_t, data_t> b(ssgrid, shalos, true);
par_SstructVector<idx_t, data_t> x(b), y(b), x0(b);
{// 填入向量数据
// 右端项设为1.0
data_t * vec_buf = new data_t [my_nelems];
for (idx_t i = 0; i < my_nelems; i++)
vec_buf[i] = 1.0;
b.set_box_values(my_part, my_ilower, box_ends, vec_buf);
// 初始解向量
for (idx_t i0 = my_ilower[0]; i0 <= my_iupper[0]; i0++)
for (idx_t i1 = my_ilower[1]; i1 <= my_iupper[1]; i1++)
for (idx_t i2 = my_ilower[2]; i2 <= my_iupper[2]; i2++) {
const idx_t elem_id = ((i0 - my_ilower[0]) * (my_iupper[1] - my_ilower[1] + 1)
+ i1 - my_ilower[1] )* (my_iupper[2] - my_ilower[2] + 1)
+ i2 - my_ilower[2] ;
vec_buf[elem_id] = ((data_t)my_part + 1.0) * (0.0 + 1.0) * cos((data_t)(i0 + i1 + i2) / 10.0 );
}
x0.set_box_values(my_part, my_ilower, box_ends, vec_buf);
// 辅助向量
y.set_val(0.0, true);
delete [] vec_buf; vec_buf = nullptr;
}
const idx_t amr_stride = 2;
assert(amr_stride == 2);
const idx_t c_lbdr = ncells_per_dim / 4 - 1,// 原网格中边界处较下者
c_ubdr = ncells_per_dim / 4 * 3 ;// 原网格中边界处较上者
if (my_pid == 0) printf("lbdr/ubdr @ C: %d %d\n", c_lbdr, c_ubdr);
// 根据半结构网格建立矩阵
__int128_t masks[my_nblks]; for (idx_t k = 0; k < my_nblks; k++) masks[k] = stencil_mask_3d7;
par_SstructMatrix<idx_t, data_t, data_t> A(ssgrid, shalos, masks);
int proc_diag_nrows = my_nelems;
int proc_offd_nnz = 0;
{// 填入矩阵数据
// 首先处理对角块,也即结构化部分
data_t* mat_buf = new data_t [my_nelems * num_diag];
#pragma omp parallel for collapse(2) schedule(static)
for (idx_t i0 = my_ilower[0]; i0 <= my_iupper[0]; i0++)
for (idx_t i1 = my_ilower[1]; i1 <= my_iupper[1]; i1++)
for (idx_t i2 = my_ilower[2]; i2 <= my_iupper[2]; i2++) {
data_t* dst_ptr = mat_buf + (((i0 - my_ilower[0]) * (my_iupper[1] - my_ilower[1] + 1)
+ i1 - my_ilower[1] )* (my_iupper[2] - my_ilower[2] + 1)
+ i2 - my_ilower[2] ) * num_diag;
dst_ptr[0] = dst_ptr[1] = dst_ptr[2] = -1.0;
dst_ptr[3] = 6.0;
dst_ptr[4] = dst_ptr[5] = dst_ptr[6] = -1.0;
// Set boundary conditions
if (i0 == 0 ) dst_ptr[0] = 0.0;
if (i0 == ncells_per_dim - 1) dst_ptr[6] = 0.0;
if (i1 == 0 ) dst_ptr[1] = 0.0;
if (i1 == ncells_per_dim - 1) dst_ptr[5] = 0.0;
if (i2 == 0 ) dst_ptr[2] = 0.0;
if (i2 == ncells_per_dim - 1) dst_ptr[4] = 0.0;
if (my_part == 0) {// 如果本进程处于原网格
// Zero out dummy unknowns (原网格被加密的区域)
if (i0 > c_lbdr && i0 < c_ubdr && i1 > c_lbdr && i1 < c_ubdr && i2 > c_lbdr && i2 < c_ubdr) {
dst_ptr[3] = 1.0;
dst_ptr[0] = dst_ptr[1] = dst_ptr[2] = dst_ptr[4] = dst_ptr[5] = dst_ptr[6] = 0.0;
}
// Zero out off-diagonal stencil couplings at fine/coarse interface (原网格与被加密部分接壤的区域)
// And Fix diagonal entries at part boundaries
if (i1 > c_lbdr && i1 < c_ubdr && i2 > c_lbdr && i2 < c_ubdr) {
if (i0 == c_lbdr) { dst_ptr[6] = 0.0; dst_ptr[3] = 7.666666666666666; }
if (i0 == c_ubdr) { dst_ptr[0] = 0.0; dst_ptr[3] = 7.666666666666666; }
}
if (i0 > c_lbdr && i0 < c_ubdr && i2 > c_lbdr && i2 < c_ubdr) {
if (i1 == c_lbdr) { dst_ptr[5] = 0.0; dst_ptr[3] = 7.666666666666666; }
if (i1 == c_ubdr) { dst_ptr[1] = 0.0; dst_ptr[3] = 7.666666666666666; }
}
if (i0 > c_lbdr && i0 < c_ubdr && i1 > c_lbdr && i1 < c_ubdr) {
if (i2 == c_lbdr) { dst_ptr[4] = 0.0; dst_ptr[3] = 7.666666666666666; }
if (i2 == c_ubdr) { dst_ptr[2] = 0.0; dst_ptr[3] = 7.666666666666666; }
}
}
else {// 如果本进程处于细网格
idx_t cnt_at_fbdr = 0;
if (i0 == 0 ) cnt_at_fbdr ++;
if (i0 == ncells_per_dim - 1) cnt_at_fbdr ++;
if (i1 == 0 ) cnt_at_fbdr ++;
if (i1 == ncells_per_dim - 1) cnt_at_fbdr ++;
if (i2 == 0 ) cnt_at_fbdr ++;
if (i2 == ncells_per_dim - 1) cnt_at_fbdr ++;
assert(cnt_at_fbdr <= 3);
// if (cnt_at_fbdr > 0) printf("Proc %d (%d,%d,%d) cnt %d\n", my_pid, i0, i1, i2, cnt_at_fbdr);
if (cnt_at_fbdr == 1) dst_ptr[3] = 5.666666666666666;// Fine part 2D borders (即加密网格的6个面)
else if (cnt_at_fbdr == 2) dst_ptr[3] = 5.333333333333333;// Fine part 1D borders (即加密网格的12条棱)
else if (cnt_at_fbdr == 3) dst_ptr[3] = 5.0 ;// Fine part 0D borders (即加密网格的8个顶点)
}
}
A.set_box_values(my_part, my_ilower, box_ends, mat_buf);
delete [] mat_buf; mat_buf = nullptr;
// 然后处理非对角快,也即非结构部分
data_t offd_val = -0.666666666666666;// 添加上非stencil的非零元数值
A.init_offd();
std::vector< Entry<idx_t, data_t> > all_nnz;
if (my_part == 0) {// 原来的网格
idx_t ngb_part = 1;
for (idx_t d = 2; d >= 0; d--) {// 在三个方向逐次添加连接关系
if (my_ilower[d] <= c_lbdr && c_lbdr <= my_iupper[d]) {
idx_t bdr_ilower[3], bdr_iupper[3];// 确定原网格上的边界位置
for (idx_t _k = 0; _k < 3; _k++) {
if (_k == d) {
bdr_ilower[_k] = c_lbdr;
bdr_iupper[_k] = c_lbdr;
} else {
bdr_ilower[_k] = std::max(c_lbdr + 1, my_ilower[_k]);
bdr_iupper[_k] = std::min(c_ubdr - 1, my_iupper[_k]);
}
}
// 从粗往细看,自己的一个粗点对应4个细点
for (idx_t fngb = 0; fngb < 4; fngb ++) {
idx_t offset[3];
if (d == 0) {
offset[0] = __builtin_popcount(0 ); offset[1] = __builtin_popcount(fngb & 0b01); offset[2] = __builtin_popcount(fngb & 0b10);
} else if (d == 1) {
offset[0] = __builtin_popcount(fngb & 0b01); offset[1] = __builtin_popcount(0 ); offset[2] = __builtin_popcount(fngb & 0b10);
} else if (d == 2) {
offset[0] = __builtin_popcount(fngb & 0b01); offset[1] = __builtin_popcount(fngb & 0b10); offset[2] = __builtin_popcount(0 );
}
for (idx_t i2 = bdr_ilower[2]; i2 <= bdr_iupper[2]; i2++)
for (idx_t i1 = bdr_ilower[1]; i1 <= bdr_iupper[1]; i1++)
for (idx_t i0 = bdr_ilower[0]; i0 <= bdr_iupper[0]; i0++) {
StructDescriptor<idx_t> row, col;
row.id = my_part;
row.index[0] = i0; row.index[1] = i1; row.index[2] = i2;
col.id = ngb_part;
for (idx_t _k = 0; _k < 3; _k++) {
if (_k == d) col.index[_k] = 0;// 注意此时对应加密网格的下边界
else col.index[_k] = (row.index[_k] - (c_lbdr + 1)) * amr_stride + offset[_k];
}
// printf("index: [%d](%d, %d, %d) - to_index: [%d](%d, %d, %d)\n",
// row.id, row.index[0], row.index[1], row.index[2],
// col.id, col.index[0], col.index[1], col.index[2]);
all_nnz.push_back(Entry<idx_t, data_t>(row, col, offd_val));
}
}
}// if lower bdr included
if (my_ilower[d] <= c_ubdr && c_ubdr <= my_iupper[d]) {
idx_t bdr_ilower[3], bdr_iupper[3];
for (idx_t _k = 0; _k < 3; _k++) {
if (_k == d) {
bdr_ilower[_k] = c_ubdr;
bdr_iupper[_k] = c_ubdr;
} else {
bdr_ilower[_k] = std::max(c_lbdr + 1, my_ilower[_k]);
bdr_iupper[_k] = std::min(c_ubdr - 1, my_iupper[_k]);
}
}
// 从粗往细看,自己的一个粗点对应4个细点
for (idx_t fngb = 0; fngb < 4; fngb ++) {
idx_t offset[3];
if (d == 0) {
offset[0] = __builtin_popcount(0 ); offset[1] = __builtin_popcount(fngb & 0b01); offset[2] = __builtin_popcount(fngb & 0b10);
} else if (d == 1) {
offset[0] = __builtin_popcount(fngb & 0b01); offset[1] = __builtin_popcount(0 ); offset[2] = __builtin_popcount(fngb & 0b10);
} else if (d == 2) {
offset[0] = __builtin_popcount(fngb & 0b01); offset[1] = __builtin_popcount(fngb & 0b10); offset[2] = __builtin_popcount(0 );
}
for (idx_t i2 = bdr_ilower[2]; i2 <= bdr_iupper[2]; i2++)
for (idx_t i1 = bdr_ilower[1]; i1 <= bdr_iupper[1]; i1++)
for (idx_t i0 = bdr_ilower[0]; i0 <= bdr_iupper[0]; i0++) {
StructDescriptor<idx_t> row, col;
row.id = my_part;
row.index[0] = i0; row.index[1] = i1; row.index[2] = i2;
col.id = ngb_part;
for (idx_t _k = 0; _k < 3; _k++) {
if (_k == d) col.index[_k] = ncells_per_dim - 1;// 注意此时对应加密网格的下边界
else col.index[_k] = (row.index[_k] - (c_lbdr + 1)) * amr_stride + offset[_k];
}
// printf("index: [%d](%d, %d, %d) - to_index: [%d](%d, %d, %d)\n",
// row.id, row.index[0], row.index[1], row.index[2],
// col.id, col.index[0], col.index[1], col.index[2]);
all_nnz.push_back(Entry<idx_t, data_t>(row, col, offd_val));
}
}
}// if upper bdr included
}
}
MPI_Barrier(MPI_COMM_WORLD);
if (my_part == 1) {// AMR加密后的网格
idx_t ngb_part = 0;
for (idx_t d = 2; d >= 0; d--) {// 在三个方向逐次添加连接关系
if (my_ilower[d] == 0) {
assert(cart_ids[d] == 0);
idx_t bdr_ilower[3], bdr_iupper[3];// 确定加密网格上的边界位置
for (idx_t _k = 0; _k < 3; _k++) {
bdr_ilower[_k] = my_ilower[_k];
if (_k == d) bdr_iupper[_k] = my_ilower[_k];
else bdr_iupper[_k] = my_iupper[_k];
}
// 从细往粗看,要知道自己这个细点对应哪个粗点
for (idx_t i2 = bdr_ilower[2]; i2 <= bdr_iupper[2]; i2++)
for (idx_t i1 = bdr_ilower[1]; i1 <= bdr_iupper[1]; i1++)
for (idx_t i0 = bdr_ilower[0]; i0 <= bdr_iupper[0]; i0++) {
StructDescriptor<idx_t> row, col;
row.id = my_part;
row.index[0] = i0; row.index[1] = i1; row.index[2] = i2;
col.id = ngb_part;
for (idx_t _k = 0; _k < 3; _k++) {
if (_k == d) col.index[_k] = c_lbdr;// 注意此时对应原网格上与加密网格的下边界
else col.index[_k] = row.index[_k] / amr_stride + c_lbdr + 1;
}
// printf("index: [%d](%d, %d, %d) - to_index: [%d](%d, %d, %d)\n",
// row.id, row.index[0], row.index[1], row.index[2],
// col.id, col.index[0], col.index[1], col.index[2]);
all_nnz.push_back(Entry<idx_t, data_t>(row, col, offd_val));
}
}
if (my_iupper[d] == ncells_per_dim - 1) {
assert(cart_ids[d] == np_per_dim - 1);
idx_t bdr_ilower[3], bdr_iupper[3];
for (idx_t _k = 0; _k < 3; _k++) {
bdr_iupper[_k] = my_iupper[_k];
if (_k == d) bdr_ilower[_k] = my_iupper[_k];
else bdr_ilower[_k] = my_ilower[_k];
}
for (idx_t i2 = bdr_ilower[2]; i2 <= bdr_iupper[2]; i2++)
for (idx_t i1 = bdr_ilower[1]; i1 <= bdr_iupper[1]; i1++)
for (idx_t i0 = bdr_ilower[0]; i0 <= bdr_iupper[0]; i0++) {
StructDescriptor<idx_t> row, col;
row.id = my_part;
row.index[0] = i0; row.index[1] = i1; row.index[2] = i2;
col.id = ngb_part;
for (idx_t _k = 0; _k < 3; _k++) {
if (_k == d) col.index[_k] = c_ubdr;// 注意此时对应原网格上与加密网格的上边界
else col.index[_k] = row.index[_k] / amr_stride + c_lbdr + 1;
}
// printf("index: [%d](%d, %d, %d) - to_index: [%d](%d, %d, %d)\n",
// row.id, row.index[0], row.index[1], row.index[2],
// col.id, col.index[0], col.index[1], col.index[2]);
all_nnz.push_back(Entry<idx_t, data_t>(row, col, offd_val));
}
}
}
}
A.add_entries(all_nnz.size(), all_nnz.data());
proc_offd_nnz = all_nnz.size();
}
A.assemble();
// for (int p = 0; p < num_procs; p++) {
// if (p == my_pid) {
// printf("Proc %4d Diag nrows %8d Offd nnz %8d\n", p, proc_diag_nrows, proc_offd_nnz);
// fflush(stdout);
// }
// MPI_Barrier(MPI_COMM_WORLD);
// }
const int test_cnt = 10;
std::vector<TEST_RECORD> records;
for (int test = 0; test < test_cnt; test++) {
vec_copy(x0, x);
double ck = vec_dot<idx_t, data_t, double>(b, b);
if (my_pid == 0) printf("( b, b) = %.15e\n", ck);
ck = vec_dot<idx_t, data_t, double>(x, x);
if (my_pid == 0) printf("( x, x) = %.15e\n", ck);
A.Mult(b, y, false);
ck = vec_dot<idx_t, data_t, double>(y, y);
if (my_pid == 0) printf("(A*b, A*b) = %.15e\n", ck);
A.Mult(x, y, false);
ck = vec_dot<idx_t, data_t, double>(y, y);
if (my_pid == 0) printf("(A*x, A*x) = %.15e\n", ck);
// 用A*x作为右端项b
vec_copy(y, b);
// 初始解设为0
x.set_val(0.0, true);
TEST_CONFIG config;
config.my_nblks = my_nblks;
config.config_mg_file = config_mg_file;
config.ssgrid_ptr = & ssgrid;
config.rtol = 1.0e-7;
TEST_RECORD rec;
buildup_solver(its_name, prc_name, config);
setup_and_solve(A, b, x, rec);
data_t true_r_norm, b_norm;
check_residual(A, x, b, y, true_r_norm, b_norm);
if (my_pid == 0) {
printf("\033[1;35mtrue ||r|| = %20.16e ||r||/||b||= %20.16e\033[0m\n",
true_r_norm, true_r_norm / b_norm);
printf("Proc %d Setup, Solve costs %.6f %.6f s\n",
my_pid, rec.setup, rec.solve);
}
stat_part_times(rec);
records.push_back(rec);
destroy_solver();
}// test loop
if (my_pid == 0) {// 输出最佳时间
stat_multi_runs(records);
}
}// all Semi-** object must be destroyed before MPI_Finalize()
SStructMG_Finalize();
MPI_Finalize();
return 0;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。