分子 MC 模拟未平衡
Molecular MC simulation is not equilibrating
假设,聚合物链中有 N 个单体。我想使用 bead-spring 模型模拟它的运动。但是,没有应用周期性边界条件。因为,生成的点永远不会越过边界。
所以,我写了下面的程序。
我正在使用 100 万步。能量没有像预期的那样波动。几千步后曲线完全平坦。
X轴是步数。 Y轴是总能量。
任何人都可以检查源代码并告诉我应该更改什么吗?
N.B。我特别关心计算聚合物总能量的函数。
可能算法不正确
public double GetTotalPotential()
{
double totalBeadPotential = 0.0;
double totalSpringPotential = 0.0;
// calculate total bead-energy
for (int i = 0; i < beadsList.Count; i++)
{
Bead item_i = beadsList[i];
Bead item_i_plus_1 = null;
try
{
item_i_plus_1 = beadsList[i + 1];
if (i != beadsList.Count - 1)
{
// calculate total spring energy.
totalSpringPotential += item_i.GetHarmonicPotential(item_i_plus_1);
}
}
catch { }
for (int j = 0; j < beadsList.Count; j++)
{
if (i != j)
{
Bead item_j = beadsList[j];
totalBeadPotential += item_i.GetPairPotential(item_j);
//Console.Write(totalBeadPotential + "\n");
//Thread.Sleep(100);
}
}
}
return totalBeadPotential + totalSpringPotential;
}
此应用程序的问题是模拟 (Simulation.SimulateMotion
) 在与绘制计时器 (SimulationGuiForm.timer1_Tick
) 并行的单独线程中 运行 并共享相同的状态 (polymerChain
) 没有任何 sync/signaling,所以 polymerChain
的一些突变被完全跳过(未绘制)并且当模拟完成时(远远早于绘图完成) timer1_Tick
将重绘同样的polymerChain
。您可以通过向 Simulation
添加计数器并在 SimulateMotion
:
中增加它来轻松检查
public class Simulation
{
public static int Simulations = 0; // counter
public static void SimulateMotion(PolymerChain polymerChain, int iterations)
{
Random random = new Random();
for (int i = 0; i < iterations; i++)
{
Simulations++; // bump the counter
// rest of the code
// ...
并在 timer1_Tick
中检查:
private void timer1_Tick(object sender, EventArgs e)
{
// ...
// previous code
if (Simulation.Simulations == totalIterations)
{
// breakpoint or Console.Writeline() ...
// will be hit as soon as "the curve goes totally flat"
}
DrawZGraph();
}
您需要以 SimulateMotion
将迭代存储在由 timer1_Tick
使用的某个集合中的方式重写您的应用程序(基本上实现 producer-consumer 模式,例如您可以尝试使用 BlockingCollection
, like I do in the pull request) 或仅在呈现当前状态时执行其操作。
假设,聚合物链中有 N 个单体。我想使用 bead-spring 模型模拟它的运动。但是,没有应用周期性边界条件。因为,生成的点永远不会越过边界。
所以,我写了下面的程序。
我正在使用 100 万步。能量没有像预期的那样波动。几千步后曲线完全平坦。
X轴是步数。 Y轴是总能量。
任何人都可以检查源代码并告诉我应该更改什么吗?
N.B。我特别关心计算聚合物总能量的函数。
可能算法不正确
public double GetTotalPotential()
{
double totalBeadPotential = 0.0;
double totalSpringPotential = 0.0;
// calculate total bead-energy
for (int i = 0; i < beadsList.Count; i++)
{
Bead item_i = beadsList[i];
Bead item_i_plus_1 = null;
try
{
item_i_plus_1 = beadsList[i + 1];
if (i != beadsList.Count - 1)
{
// calculate total spring energy.
totalSpringPotential += item_i.GetHarmonicPotential(item_i_plus_1);
}
}
catch { }
for (int j = 0; j < beadsList.Count; j++)
{
if (i != j)
{
Bead item_j = beadsList[j];
totalBeadPotential += item_i.GetPairPotential(item_j);
//Console.Write(totalBeadPotential + "\n");
//Thread.Sleep(100);
}
}
}
return totalBeadPotential + totalSpringPotential;
}
此应用程序的问题是模拟 (Simulation.SimulateMotion
) 在与绘制计时器 (SimulationGuiForm.timer1_Tick
) 并行的单独线程中 运行 并共享相同的状态 (polymerChain
) 没有任何 sync/signaling,所以 polymerChain
的一些突变被完全跳过(未绘制)并且当模拟完成时(远远早于绘图完成) timer1_Tick
将重绘同样的polymerChain
。您可以通过向 Simulation
添加计数器并在 SimulateMotion
:
public class Simulation
{
public static int Simulations = 0; // counter
public static void SimulateMotion(PolymerChain polymerChain, int iterations)
{
Random random = new Random();
for (int i = 0; i < iterations; i++)
{
Simulations++; // bump the counter
// rest of the code
// ...
并在 timer1_Tick
中检查:
private void timer1_Tick(object sender, EventArgs e)
{
// ...
// previous code
if (Simulation.Simulations == totalIterations)
{
// breakpoint or Console.Writeline() ...
// will be hit as soon as "the curve goes totally flat"
}
DrawZGraph();
}
您需要以 SimulateMotion
将迭代存储在由 timer1_Tick
使用的某个集合中的方式重写您的应用程序(基本上实现 producer-consumer 模式,例如您可以尝试使用 BlockingCollection
, like I do in the pull request) 或仅在呈现当前状态时执行其操作。