Skip to content

Commit 17c9547

Browse files
author
Fei Yang
committed
Optimize MDCell migration output
1 parent c5cff08 commit 17c9547

8 files changed

Lines changed: 126 additions & 66 deletions

File tree

docs/advanced/input_files/input-main.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3518,7 +3518,7 @@
35183518
### md_dumpfreq
35193519

35203520
- **Type**: Integer
3521-
- **Description**: The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output.
3521+
- **Description**: The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output; scalar MD progress remains printed to the terminal and running_md.log every step.
35223522
- **Default**: 1
35233523

35243524
### md_out_force

docs/parameters.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1465,7 +1465,7 @@ parameters:
14651465
category: Molecular dynamics
14661466
type: Integer
14671467
description: |
1468-
The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output.
1468+
The output frequency of OUT.${suffix}/MD_dump in molecular dynamics calculations, which includes lattice and atomic information. Set to 0 to disable MD_dump output; scalar MD progress remains printed to the terminal and running_md.log every step.
14691469
default_value: "1"
14701470
unit: ""
14711471
availability: ""

source/source_cell/module_neighlist/domain_decomposition.cpp

Lines changed: 99 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <limits>
1212
#include <map>
1313
#include <stdexcept>
14+
#include <utility>
1415

1516
DomainDecomposition::DomainDecomposition()
1617
: comm_(MPI_COMM_NULL),
@@ -675,66 +676,114 @@ void DomainDecomposition::accumulate_ghost_forces(std::vector<LocalAtom>& owned_
675676

676677
void DomainDecomposition::migrate_owned_atoms(std::vector<LocalAtom>& owned_atoms) const
677678
{
678-
std::vector<std::vector<PackedAtom> > send_atoms(static_cast<std::size_t>(size_));
679-
for (std::size_t i = 0; i < owned_atoms.size(); ++i)
679+
const int direction_count = 6;
680+
const int axis[direction_count] = {0, 0, 1, 1, 2, 2};
681+
const int step[direction_count] = {-1, 1, -1, 1, -1, 1};
682+
std::array<int, direction_count> neighbors;
683+
for (int idir = 0; idir < direction_count; ++idir)
680684
{
681-
LocalAtom atom = owned_atoms[i];
682-
atom.frac = wrapped_frac_from_cart(atom.cart);
683-
atom.cart = atom.frac * latvec_;
684-
atom.owner_rank = owner_rank_from_frac(atom.frac);
685-
const std::array<int, 3> no_shift = {{0, 0, 0}};
686-
send_atoms[static_cast<std::size_t>(atom.owner_rank)].push_back(pack_atom(atom, no_shift));
685+
std::array<int, 3> neighbor_coords = coords_;
686+
neighbor_coords[axis[idir]] = positive_mod(neighbor_coords[axis[idir]] + step[idir], dims_[axis[idir]]);
687+
neighbors[idir] = rank_from_coords(neighbor_coords);
687688
}
688689

689-
std::vector<int> send_counts(static_cast<std::size_t>(size_), 0);
690-
std::vector<int> recv_counts(static_cast<std::size_t>(size_), 0);
691-
for (int irank = 0; irank < size_; ++irank)
692-
{
693-
send_counts[static_cast<std::size_t>(irank)]
694-
= static_cast<int>(send_atoms[static_cast<std::size_t>(irank)].size() * sizeof(PackedAtom));
695-
}
696-
MPI_Alltoall(&send_counts[0], 1, MPI_INT, &recv_counts[0], 1, MPI_INT, comm_);
690+
std::vector<LocalAtom> pending_atoms;
691+
pending_atoms.swap(owned_atoms);
692+
std::vector<LocalAtom> retained_atoms;
693+
retained_atoms.reserve(pending_atoms.size());
694+
const std::array<int, 3> no_shift = {{0, 0, 0}};
697695

698-
std::vector<int> send_displs(static_cast<std::size_t>(size_), 0);
699-
std::vector<int> recv_displs(static_cast<std::size_t>(size_), 0);
700-
int total_send_bytes = 0;
701-
int total_recv_bytes = 0;
702-
for (int irank = 0; irank < size_; ++irank)
696+
long long global_outgoing = 0;
697+
do
703698
{
704-
send_displs[static_cast<std::size_t>(irank)] = total_send_bytes;
705-
recv_displs[static_cast<std::size_t>(irank)] = total_recv_bytes;
706-
total_send_bytes += send_counts[static_cast<std::size_t>(irank)];
707-
total_recv_bytes += recv_counts[static_cast<std::size_t>(irank)];
708-
}
699+
std::array<std::vector<PackedAtom>, direction_count> send_atoms;
700+
for (std::size_t i = 0; i < pending_atoms.size(); ++i)
701+
{
702+
LocalAtom atom = std::move(pending_atoms[i]);
703+
atom.frac = wrapped_frac_from_cart(atom.cart);
704+
atom.cart = atom.frac * latvec_;
709705

710-
std::vector<PackedAtom> send_buffer(static_cast<std::size_t>(total_send_bytes / static_cast<int>(sizeof(PackedAtom))));
711-
int send_index = 0;
712-
for (int irank = 0; irank < size_; ++irank)
713-
{
714-
const std::vector<PackedAtom>& atoms = send_atoms[static_cast<std::size_t>(irank)];
715-
for (std::size_t i = 0; i < atoms.size(); ++i)
706+
std::array<int, 3> owner_coords;
707+
const double frac[3] = {atom.frac.x, atom.frac.y, atom.frac.z};
708+
for (int idim = 0; idim < 3; ++idim)
709+
{
710+
owner_coords[idim] = std::min(static_cast<int>(std::floor(frac[idim] * dims_[idim])), dims_[idim] - 1);
711+
}
712+
atom.owner_rank = rank_from_coords(owner_coords);
713+
if (atom.owner_rank == rank_)
714+
{
715+
retained_atoms.push_back(std::move(atom));
716+
continue;
717+
}
718+
719+
int direction = -1;
720+
for (int idim = 0; idim < 3 && direction < 0; ++idim)
721+
{
722+
int delta = owner_coords[idim] - coords_[idim];
723+
if (delta > dims_[idim] / 2) delta -= dims_[idim];
724+
if (delta < -dims_[idim] / 2) delta += dims_[idim];
725+
if (delta != 0) direction = 2 * idim + (delta > 0 ? 1 : 0);
726+
}
727+
assert(direction >= 0);
728+
send_atoms[direction].push_back(pack_atom(atom, no_shift));
729+
}
730+
pending_atoms.clear();
731+
732+
std::array<int, direction_count> send_counts;
733+
std::array<int, direction_count> recv_counts;
734+
long long local_outgoing = 0;
735+
for (int idir = 0; idir < direction_count; ++idir)
716736
{
717-
send_buffer[static_cast<std::size_t>(send_index++)] = atoms[i];
737+
const std::size_t bytes = send_atoms[idir].size() * sizeof(PackedAtom);
738+
if (bytes > static_cast<std::size_t>(std::numeric_limits<int>::max()))
739+
{
740+
throw std::overflow_error("DomainDecomposition migration send count exceeds int range.");
741+
}
742+
send_counts[idir] = static_cast<int>(bytes);
743+
local_outgoing += static_cast<long long>(send_atoms[idir].size());
718744
}
719-
}
745+
MPI_Allreduce(&local_outgoing, &global_outgoing, 1, MPI_LONG_LONG, MPI_SUM, comm_);
746+
if (global_outgoing == 0) break;
720747

721-
std::vector<PackedAtom> recv_buffer(static_cast<std::size_t>(total_recv_bytes / static_cast<int>(sizeof(PackedAtom))));
722-
MPI_Alltoallv(total_send_bytes > 0 ? reinterpret_cast<const char*>(&send_buffer[0]) : 0,
723-
&send_counts[0],
724-
&send_displs[0],
725-
MPI_BYTE,
726-
total_recv_bytes > 0 ? reinterpret_cast<char*>(&recv_buffer[0]) : 0,
727-
&recv_counts[0],
728-
&recv_displs[0],
729-
MPI_BYTE,
730-
comm_);
748+
std::array<MPI_Request, 2 * direction_count> requests;
749+
for (int idir = 0; idir < direction_count; ++idir)
750+
{
751+
const int opposite = idir ^ 1;
752+
MPI_Irecv(&recv_counts[idir], 1, MPI_INT, neighbors[idir], 100 + opposite, comm_, &requests[idir]);
753+
MPI_Isend(&send_counts[idir], 1, MPI_INT, neighbors[idir], 100 + idir, comm_, &requests[direction_count + idir]);
754+
}
755+
MPI_Waitall(2 * direction_count, &requests[0], MPI_STATUSES_IGNORE);
731756

732-
owned_atoms.clear();
733-
owned_atoms.reserve(recv_buffer.size());
734-
for (std::size_t i = 0; i < recv_buffer.size(); ++i)
735-
{
736-
owned_atoms.push_back(unpack_owned_atom(recv_buffer[i]));
737-
}
757+
std::array<std::vector<PackedAtom>, direction_count> recv_atoms;
758+
for (int idir = 0; idir < direction_count; ++idir)
759+
{
760+
if (recv_counts[idir] < 0 || recv_counts[idir] % static_cast<int>(sizeof(PackedAtom)) != 0)
761+
{
762+
throw std::runtime_error("Invalid DomainDecomposition migration receive count.");
763+
}
764+
recv_atoms[idir].resize(static_cast<std::size_t>(recv_counts[idir] / static_cast<int>(sizeof(PackedAtom))));
765+
}
766+
767+
for (int idir = 0; idir < direction_count; ++idir)
768+
{
769+
const int opposite = idir ^ 1;
770+
MPI_Irecv(recv_atoms[idir].empty() ? NULL : reinterpret_cast<char*>(&recv_atoms[idir][0]),
771+
recv_counts[idir], MPI_BYTE, neighbors[idir], 200 + opposite, comm_, &requests[idir]);
772+
MPI_Isend(send_atoms[idir].empty() ? NULL : reinterpret_cast<const char*>(&send_atoms[idir][0]),
773+
send_counts[idir], MPI_BYTE, neighbors[idir], 200 + idir, comm_, &requests[direction_count + idir]);
774+
}
775+
MPI_Waitall(2 * direction_count, &requests[0], MPI_STATUSES_IGNORE);
776+
777+
for (int idir = 0; idir < direction_count; ++idir)
778+
{
779+
for (std::size_t i = 0; i < recv_atoms[idir].size(); ++i)
780+
{
781+
pending_atoms.push_back(unpack_owned_atom(recv_atoms[idir][i]));
782+
}
783+
}
784+
} while (global_outgoing > 0);
785+
786+
owned_atoms.swap(retained_atoms);
738787
}
739788

740789
#endif // __MPI

source/source_cell/module_neighlist/test/md_cell_migrate_mpi_test.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <mpi.h>
77

88
#include <cstdint>
9+
#include <mpi.h>
910
#include <string>
1011
#include <vector>
1112

@@ -71,6 +72,15 @@ TEST(MdCellMigrateMpiTest, AtomCrossingDomainMigratesToNewOwner)
7172
ASSERT_EQ(mdcell.mpi_size(), size);
7273
if (size == 2)
7374
{
75+
ASSERT_EQ(mdcell.nlocal(), 1);
76+
mdcell.mutable_owned_atoms()[0].vel.x = static_cast<double>(rank + 1);
77+
mdcell.mutable_owned_atoms()[0].force.y = static_cast<double>(rank + 3);
78+
mdcell.migrate_owned_atoms();
79+
ASSERT_EQ(mdcell.nlocal(), 1);
80+
EXPECT_EQ(mdcell.owned_atoms()[0].owner_rank, rank);
81+
EXPECT_EQ(mdcell.owned_atoms()[0].vel.x, static_cast<double>(rank + 1));
82+
EXPECT_EQ(mdcell.owned_atoms()[0].force.y, static_cast<double>(rank + 3));
83+
7484
if (rank == 0 && mdcell.nlocal() == 1)
7585
{
7686
mdcell.mutable_owned_atoms()[0].cart.x = 0.8;

source/source_io/module_output/output_log.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,10 @@ void print_force(std::ofstream& ofs, const MDCell& cell, const std::string& name
293293
};
294294

295295
#ifdef __MPI
296-
const int rank = cell.mpi_rank();
297-
const int size = cell.mpi_size();
296+
int rank = 0;
297+
int size = 1;
298+
MPI_Comm_rank(cell.communicator(), &rank);
299+
MPI_Comm_size(cell.communicator(), &size);
298300
if (rank != 0)
299301
{
300302
const int nlocal = cell.nlocal();

source/source_md/run_md.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,10 @@ void md_line(MDCell& mdcell,
8686
mdrun->frozen_freedom_);
8787
}
8888

89+
mdrun->print_md(GlobalV::ofs_running, PARAM.inp.cal_stress);
8990
if (param_in.mdp.md_dumpfreq > 0
9091
&& (mdrun->step_ + mdrun->step_rst_) % param_in.mdp.md_dumpfreq == 0)
9192
{
92-
mdrun->print_md(GlobalV::ofs_running, PARAM.inp.cal_stress);
93-
9493
MD_func::dump_info(mdrun->step_ + mdrun->step_rst_,
9594
PARAM.globalv.global_out_dir,
9695
mdcell,
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
etotref -2.234489982055187
2-
etotperatomref -0.0698278119
3-
totalforceref 2.434994
4-
totalstressref 28.475724
5-
totaltimeref 0.03
1+
etotref -2.239520155656396
2+
etotperatomref -0.0699850049
3+
totalforceref 2.331355
4+
totalstressref 28.360820
5+
totaltimeref 0.02
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
etotref -2.242881714733034
2-
etotperatomref -0.0700900536
3-
totalforceref 2.351158
4-
totalstressref 28.243185
5-
totaltimeref 0.04
1+
etotref -2.24671151561839
2+
etotperatomref -0.0702097349
3+
totalforceref 2.191421
4+
totalstressref 28.146284
5+
totaltimeref 0.02

0 commit comments

Comments
 (0)