计算值的意外收敛,你能帮我弄清楚原因吗?

时间:2014-12-06 23:20:59

标签: c++ physics physics-engine

我正在编写一个分子动力学程序来创建一个晶格并用原子/分子填充它。然后给它们随机速度并初始化系统。然后,在整个时间内,分子彼此相互作用并相互施加力。

我试图让我的程序尽可能可读。

我的问题是当代码运行时,我感兴趣的所有内容的值,主要是矢量_tempreture,_pressure,_totalEnergy,_interactionEnergy,_kineticEnergy似乎都会收敛(在5次运行后)到某些值。这些值在其余的运行中不会发生变化,有时会随机出现峰值,然后再下降。

我无法弄清楚我的代码出乎意料的行为,而且我几个小时都在看它。我希望你们中的一个聪明人能够帮助我。

//in MD.h

#ifndef MD_H
#define MD_H

#include <iostream>
#include <random>
#include <time.h>
#include <vector>
#include <string>
#include <fstream>

class MD{
public:
    MD();
    ~MD();
    void initLatice();
    void simulate(int _runs);
    void wrtieToFile(std::string fileName);
    double randomValue(double upper, double lower);
private:
    double _nMolecules;
    double _estKineticEnergy;
    double _dt;
    double _density;
    bool _tempscale;
    double _energyCorrection;
    double _pressureCorrection;
    double _nFCC = 4;
    double _truncationSeperation;
    double _sidelength;
    double _pi = 3.142;
    std::vector<double> x_data, y_data, z_data;
    std::vector<double> _vX, _vY, _vZ;
    std::vector<double> _xPos, _yPos, _zPos;
    std::vector<double> _totalEnergy, _kineticEnergy, _interactionEnergy, _pressure, _tempreture;
    std::vector<double> _radialDist, _radialDistCoord;
};

#endif

如果有人想知道下一个文件没有包含writeToFile的定义,我决定不在此处粘贴它以节省空间。

//in MD.cpp
#include "MD.h"

MD::MD() : _radialDist(201, 0.0), _radialDistCoord(201, 0.0) {
        _dt = 0.005;
        _density = 1.0;
        _tempscale = true;
        _nMolecules = pow(_nFCC, 3) * 4;
        x_data = { 0.25, 0.75, 0.75, 0.25 };
        y_data = { 0.25, 0.75, 0.25, 0.75 };
        z_data = { 0.25, 0.25, 0.75, 0.75 };
        _sidelength = pow((_nFCC / _density), 1. / 3.);
        _truncationSeperation = 2.5;
        if (_truncationSeperation > _sidelength / 2.0)
            _truncationSeperation = _sidelength / 2.0;
        _energyCorrection = (8.0 * _pi * _density)*(1.0 / (9.0 * pow(_truncationSeperation, 9)) - 1 / (3.0 * pow(_truncationSeperation, 3)));
        _pressureCorrection = (16.0 * _pi * pow(_density, 2))*(2.0 / (9.0 * pow(_truncationSeperation, 9)) - 1 / (3.0 * pow(_truncationSeperation, 3)));
}

MD::~MD(){}

double MD::randomValue(double upper, double lower)
{
    double returnValue;
    do{
        returnValue = upper + (rand() / (RAND_MAX / (lower - upper)));
    } while (returnValue > upper || returnValue < lower);
    return returnValue;
}

void MD::initLatice(){
    int count = 0;
    double x_init = 0, y_init = 0, z_init = 0;
    double _tempreture = 1.0;
    _estKineticEnergy = 0.5 * (3.0 * _nMolecules - 4.0) * _tempreture;
    srand(time(NULL));

    for (int i = 0; i < 4; i++){
        for (int a = 1; a <= _nFCC; a++){
            for (int b = 1; b <= _nFCC; b++){
                for (int c = 1; c <= _nFCC; c++){
                    _xPos.push_back(_sidelength*(a - 1 + x_data[i]) / _nFCC);
                    _vX.push_back(randomValue(0.5, -0.5));
                    x_init += _vX[count] / _nMolecules;

                    _yPos.push_back(_sidelength*(b - 1 + y_data[i]) / _nFCC);
                    _vY.push_back(randomValue(0.5, -0.5));
                    y_init += _vY[count] / _nMolecules;

                    _zPos.push_back(_sidelength*(c - 1 + z_data[i]) / _nFCC);
                    _vZ.push_back(randomValue(0.5, -0.5));
                    z_init += _vZ[count] / _nMolecules;

                    count++;
                }
            }
        }
    }

    double velocityScale = 0, kineticEnergy = 0;

    for (int i = 0; i < _nMolecules; i++){
        _vX[i] -= x_init;
        _vY[i] -= y_init;
        _vZ[i] -= z_init;
        kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
    }

    velocityScale = sqrt(_estKineticEnergy / kineticEnergy);

    for (int i = 0; i < _nMolecules; i++){
        _vX[i] = _vX[i] * velocityScale;
        _vY[i] = _vY[i] * velocityScale;
        _vZ[i] = _vZ[i] * velocityScale;
    }
}

void MD::simulate(int _runs){
    double force = 0;
    double seperationSquared = 0;
    double interactionEnergy = 0;
    double kineticEnergy = 0;
    double pressure = 0;

    for (int run = 0; run <= _runs; run++){
        interactionEnergy = 0;
        pressure = 0;
        std::vector<double> force_x(256, 0.0);
        std::vector<double> force_y(256, 0.0);
        std::vector<double> force_z(256, 0.0);

        for (int i = 0; i < _nMolecules - 1; i++){
            double xI = _xPos[i], yI = _yPos[i], zI = _zPos[i];
            for (int j = i + 1; j < _nMolecules; j++){
                double x = xI - _xPos[j];
                double y = yI - _yPos[j];
                double z = zI - _zPos[j];

                if (x > _sidelength / 2.0)
                    x -= _sidelength;
                if (y > _sidelength / 2.0)
                    y -= _sidelength;
                if (z > _sidelength / 2.0)
                    z -= _sidelength;
                if (x < -_sidelength / 2.0)
                    x += _sidelength;
                if (y < -_sidelength / 2.0)
                    y += _sidelength;
                if (z < -_sidelength / 2.0)
                    z += _sidelength;

                seperationSquared = pow(x, 2) + pow(y, 2) + pow(z, 2);

                if (seperationSquared <= (pow(_truncationSeperation, 2))){
                    interactionEnergy += 4. * ((1. / pow(seperationSquared, 6)) - (1. / pow(seperationSquared, 3)));
                    force = 24. * ((2. / pow(seperationSquared, 7)) - (1. / pow(seperationSquared, 4)));
                    force_x[i] += x * force;
                    force_y[i] += y * force;
                    force_z[i] += z * force;
                    force_x[j] -= x * force;
                    force_y[j] -= y * force;
                    force_z[j] -= z * force;
                    pressure += force * seperationSquared;

                    int histCounter = ceil(sqrt(seperationSquared) * (200.0/_truncationSeperation));
                    _radialDist[histCounter] += 1.0;
                }
            }
        }

        //thermostating
        double velocityScale = 0;

        if (_tempscale == true){
            kineticEnergy = 0;
            for (int i = 0; i < _nMolecules; i++)
                kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));
            velocityScale = sqrt(_estKineticEnergy / kineticEnergy);
        } 
        else { velocityScale = 1.0; }

        kineticEnergy = 0;

        //applying verlets leapfrog algorithm
        for (int i = 0; i < _nMolecules; i++){
            _vX[i] = _vX[i] * velocityScale + force_x[i] * _dt;
            _xPos[i] += _vX[i] * _dt;

            _vY[i] = _vY[i] * velocityScale + force_y[i] * _dt;
            _yPos[i] += _vY[i] * _dt;

            _vZ[i] = _vZ[i] * velocityScale + force_z[i] * _dt;
            _zPos[i] += _vZ[i] * _dt;

            kineticEnergy += 0.5 * (pow(_vX[i], 2) + pow(_vY[i], 2) + pow(_vZ[i], 2));

            //check if the particle is still within the box
            if (_xPos[i] > _sidelength)
                _xPos[i] -= _sidelength;
            if (_yPos[i] > _sidelength)
                _yPos[i] -= _sidelength;
            if (_zPos[i] > _sidelength)
                _zPos[i] -= _sidelength;
            if (_xPos[i] < 0.0)
                _xPos[i] += _sidelength;
            if (_yPos[i] < 0.0)
                _yPos[i] += _sidelength;
            if (_zPos[i] < 0.0)
                _zPos[i] += _sidelength;
        }

        _kineticEnergy.push_back(kineticEnergy / _nMolecules);
        _interactionEnergy.push_back((interactionEnergy / _nMolecules) + _energyCorrection);
        _totalEnergy.push_back(_kineticEnergy[run] + _interactionEnergy[run]);

        if (_tempscale == true)
            _tempreture.push_back(_nMolecules * 2. * _kineticEnergy[run] / (3.0 * _nMolecules - 4.0));
        else
            _tempreture.push_back(_nMolecules * 2. * _kineticEnergy[run] / (3.0 * _nMolecules - 3.0));

        _pressure.push_back((2.0 * _kineticEnergy[run] * _nMolecules + pressure) / (3.0*(pow(_sidelength, 3) + _pressureCorrection)));
    }

    for (int i = 1; i <= 200; i++){
        double r = i * _truncationSeperation / 200.0;
        _radialDistCoord[i] = _radialDistCoord[i - 1] + 2.0 * _radialDist[i] * 10 / _runs / _nMolecules;
        _radialDist[i] = _radialDist[i] / (2.0*_pi*r*r*(_truncationSeperation/200.0)*_density*_runs*_nMolecules);
    }


}

最后......

//in main.cpp
#include "MD.h"

int main(){
    MD myMD;
    myMD.initLatice();
    myMD.simulate(400);
    std::string fileName = "myFile.txt";
    myMD.wrtieToFile(fileName);
    return 0;
}

非常感谢!

0 个答案:

没有答案