Operator= 减慢模拟速度
Operator= slowing down simulation
我正在运行宁Monte Carlo聚合物模拟。系统当前状态的整个配置由名为 Grid
的对象给出。这是我对 Grid
:
的定义
class Grid{
public:
std::vector <Polymer> PolymersInGrid; // all the polymers in the grid
int x; // length of x-edge of grid
int y; // length of y-edge of grid
int z; // length of z-edge of grid
double kT; // energy factor
double Emm_n ; // monomer-solvent when Not aligned
double Emm_a ; // monomer-solvent when Aligned
double Ems; // monomer-solvent interaction
double Energy; // energy of grid
std::map <std::vector <int>, Particle> OccupancyMap; // a map that gives the particle given the location
Grid(int xlen, int ylen, int zlen, double kT_, double Emm_a_, double Emm_n_, double Ems_): x (xlen), y (ylen), z (zlen), kT (kT_), Emm_n(Emm_n_), Emm_a (Emm_a_), Ems (Ems_) { // Constructor of class
// this->instantiateOccupancyMap();
};
// Destructor of class
~Grid(){
};
// assignment operator that allows for a correct transfer of properties. Important to functioning of program.
Grid& operator=(Grid other){
std::swap(PolymersInGrid, other.PolymersInGrid);
std::swap(Energy, other.Energy);
std::swap(OccupancyMap, other.OccupancyMap);
return *this;
}
.
.
.
}
如果需要,我可以详细介绍对象 Polymer
和 Particle
。
在我的驱动程序代码中,这就是我要做的:
定义最大迭代次数。
- 定义完整的网格
G
。
- 正在创建名为
G_
的 G
副本。
- 我正在扰乱
G_
的配置。
- 如果根据 Metropolis 标准接受
G_
上的扰动,我将 G_
分配给 G
(G=G_
)。
- 重复步骤 1-4 直到达到最大迭代次数。
这是我的驱动代码:
auto start = std::chrono::high_resolution_clock::now();
Grid G_ (G);
int acceptance_count = 0;
for (int i{1}; i< (Nmov+1); i++){
// choose a move
G_ = MoveChooser(G, v);
if ( MetropolisAcceptance (G.Energy, G_.Energy, G.kT) ) {
// accepted
// replace old config with new config
acceptance_count++;
std::cout << "Number of acceptances is " << acceptance_count << std::endl;
G = G_;
}
else {
// continue;
}
if (i % dfreq == 0){
G.dumpPositionsOfPolymers (i, dfile) ;
G.dumpEnergyOfGrid(i, efile, call) ;
}
// G.PolymersInGrid.at(0).printChainCoords();
}
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds> (stop-start);
std::cout << "\n\nTime taken for simulation: " << duration.count() << " milliseconds" << std::endl;
这是有趣的部分:如果我 运行 使用没有很多“接受”(低温、不良溶剂)的条件进行模拟,则模拟 运行 非常快。然而,如果有大量的接受,模拟就会变得非常慢。 我的假设是我的赋值运算符 = 正在减慢我的模拟速度。
我 运行 一些测试:
接受数 = 25365,挂钟时间 = 717770 毫秒 (!)
接受次数 = 2165,挂钟时间 = 64412 毫秒
接受次数 = 3000,挂钟时间 = 75550 毫秒
而且这个趋势还在继续。
谁能建议我如何提高效率?有没有办法绕过我正在经历的减速,我认为,由于 = 运算符?
如果您能给我任何建议,我将不胜感激!
你当然可以做的一件事来提高性能是强制移动 _G
而不是将其应对到 G
:
G = std::move(G_);
毕竟,在这个阶段你不再需要G_
了。
旁注。您不需要复制 operator=
中的所有成员数据这一事实表明您对 Grid
的设计远非完美,但是,如果程序很小并且您确定,请保留它你控制一切。无论如何,而不是使用 operator=
,您应该定义和使用具有有意义名称的成员函数,例如“fast_and_dirty_swap
”等 :-) 然后您可以按照@建议的方式定义 operator=
Jarod42,即使用= default
.
我在 C++11 之前使用的另一种方法是对指针进行操作。在这种情况下,一个人会有两个 Grid
s,一个是“真实的”,一个被视为缓冲区或沙箱,并且在接受时将简单地交换指针,以便“缓冲区”充满 MoveChooser
将成为真实的当前 Grid
.
一个伪代码:
- 创建两个缓冲区,
previous
和 current
,每个缓冲区都能够存储模拟状态
- 初始化
current
- 创建两个指针,
p_prev = &previous
,p_curr = ¤rt
- 步数不限
- 根据
*p_curr
计算下一个状态并将其存储在*p_prev
中(例如monte_carlo_step(p_curr, p_prev)
- 交换指针:现在当前系统状态为
p_curr
,之前为 p_prev
。
- 分析存储在
*p_curr
的结果
我正在运行宁Monte Carlo聚合物模拟。系统当前状态的整个配置由名为 Grid
的对象给出。这是我对 Grid
:
class Grid{
public:
std::vector <Polymer> PolymersInGrid; // all the polymers in the grid
int x; // length of x-edge of grid
int y; // length of y-edge of grid
int z; // length of z-edge of grid
double kT; // energy factor
double Emm_n ; // monomer-solvent when Not aligned
double Emm_a ; // monomer-solvent when Aligned
double Ems; // monomer-solvent interaction
double Energy; // energy of grid
std::map <std::vector <int>, Particle> OccupancyMap; // a map that gives the particle given the location
Grid(int xlen, int ylen, int zlen, double kT_, double Emm_a_, double Emm_n_, double Ems_): x (xlen), y (ylen), z (zlen), kT (kT_), Emm_n(Emm_n_), Emm_a (Emm_a_), Ems (Ems_) { // Constructor of class
// this->instantiateOccupancyMap();
};
// Destructor of class
~Grid(){
};
// assignment operator that allows for a correct transfer of properties. Important to functioning of program.
Grid& operator=(Grid other){
std::swap(PolymersInGrid, other.PolymersInGrid);
std::swap(Energy, other.Energy);
std::swap(OccupancyMap, other.OccupancyMap);
return *this;
}
.
.
.
}
如果需要,我可以详细介绍对象 Polymer
和 Particle
。
在我的驱动程序代码中,这就是我要做的: 定义最大迭代次数。
- 定义完整的网格
G
。 - 正在创建名为
G_
的G
副本。 - 我正在扰乱
G_
的配置。 - 如果根据 Metropolis 标准接受
G_
上的扰动,我将G_
分配给G
(G=G_
)。 - 重复步骤 1-4 直到达到最大迭代次数。
这是我的驱动代码:
auto start = std::chrono::high_resolution_clock::now();
Grid G_ (G);
int acceptance_count = 0;
for (int i{1}; i< (Nmov+1); i++){
// choose a move
G_ = MoveChooser(G, v);
if ( MetropolisAcceptance (G.Energy, G_.Energy, G.kT) ) {
// accepted
// replace old config with new config
acceptance_count++;
std::cout << "Number of acceptances is " << acceptance_count << std::endl;
G = G_;
}
else {
// continue;
}
if (i % dfreq == 0){
G.dumpPositionsOfPolymers (i, dfile) ;
G.dumpEnergyOfGrid(i, efile, call) ;
}
// G.PolymersInGrid.at(0).printChainCoords();
}
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds> (stop-start);
std::cout << "\n\nTime taken for simulation: " << duration.count() << " milliseconds" << std::endl;
这是有趣的部分:如果我 运行 使用没有很多“接受”(低温、不良溶剂)的条件进行模拟,则模拟 运行 非常快。然而,如果有大量的接受,模拟就会变得非常慢。 我的假设是我的赋值运算符 = 正在减慢我的模拟速度。 我 运行 一些测试:
接受数 = 25365,挂钟时间 = 717770 毫秒 (!)
接受次数 = 2165,挂钟时间 = 64412 毫秒
接受次数 = 3000,挂钟时间 = 75550 毫秒
而且这个趋势还在继续。 谁能建议我如何提高效率?有没有办法绕过我正在经历的减速,我认为,由于 = 运算符?
如果您能给我任何建议,我将不胜感激!
你当然可以做的一件事来提高性能是强制移动 _G
而不是将其应对到 G
:
G = std::move(G_);
毕竟,在这个阶段你不再需要G_
了。
旁注。您不需要复制 operator=
中的所有成员数据这一事实表明您对 Grid
的设计远非完美,但是,如果程序很小并且您确定,请保留它你控制一切。无论如何,而不是使用 operator=
,您应该定义和使用具有有意义名称的成员函数,例如“fast_and_dirty_swap
”等 :-) 然后您可以按照@建议的方式定义 operator=
Jarod42,即使用= default
.
我在 C++11 之前使用的另一种方法是对指针进行操作。在这种情况下,一个人会有两个 Grid
s,一个是“真实的”,一个被视为缓冲区或沙箱,并且在接受时将简单地交换指针,以便“缓冲区”充满 MoveChooser
将成为真实的当前 Grid
.
一个伪代码:
- 创建两个缓冲区,
previous
和current
,每个缓冲区都能够存储模拟状态 - 初始化
current
- 创建两个指针,
p_prev = &previous
,p_curr = ¤rt
- 步数不限
- 根据
*p_curr
计算下一个状态并将其存储在*p_prev
中(例如monte_carlo_step(p_curr, p_prev)
- 交换指针:现在当前系统状态为
p_curr
,之前为p_prev
。
- 根据
- 分析存储在
*p_curr
的结果