I smooth some data using a basic Exponential Moving Average filter:
int main ()
{
double a0 = 0.1;
double input = 8.0;
double z = 0.0;
for(int i=0; i < 200; i++) {
z += a0 * (input - z);
std::cout << i << "° : "<< z << std::endl;
}
}
For some reasons, I'd like to do it every X (=8) steps.
The fact is that as for now, I don't know how to calculate it every 8° input. I still process at every input and "store" only the 8°.
How would you "save CPU" avoid to calculate it on each step? Is there a series where I can just calculate 8° value ahead?
This is the actual code I have (which smooth at each step):
int main ()
{
double a0 = 0.1;
double input = 8.0;
double z = 0.0;
int step = 8;
for(int i=0; i < 200; i+=8) {
z += a0 * (input - z);
std::cout << i << "° : "<< z << std::endl;
int j = 1;
while (j++ < step) {
z += a0 * (input - z);
}
}
}
I'd like to avoid the "7 steps of while" into a unique operation. Is it possible?
It's called an exponential moving average function for a reason: the difference (input - z0) is an exponentially decreasing function of the number of steps. In fact, after N steps the decrease is pow(1-a0,N).
Now the relevant math is pow(x,N) == pow(pow(x,8), N/8).
Related
I am trying to calculate distances between particles in a box. If the distance calculated is greater than a preset cut-off distance, then the potential energy is 0. Otherwise, it is 1.
There are some rounding issues I think and I am not familiar with variable types and passing variables through functions to know what to do next.
The error
When I calculate d0 by hand I get d0 = 0.070 - this is not what the computer gets! The computer gets a number on the order of e-310.
All of the calculated distances (dij) are no shorter than 1/14, which is much larger than e-310. According to my if statement, if dij>d0, then U=0, so I should get a total energy of 0, but this is what I get:
d0 is 6.95322e-310
i is 0 j is 1 dij is 0.0714286 d0 is 6.95322e-310 Uij is 1
.....
Energy of the system is 24976
Please let me know if I could provide any more information. I did not include the entirety of my code, but the other portion involves no manipulation of d0.
I copied the relevant pieces of code below
Part 1: relevant box data
class Vector {
public:
double x;
double y;
Vector() {
}
Vector (double x_, double y_) {
x = x_;
y = y_;
}
double len() {
return sqrt(x*x + y*y);
}
double lenSqr() {
return x*x + y*y;
}
};
class Atom
{
public:
Vector pos;
Vector vel;
Vector force;
Atom (double x_, double y_) {
pos = Vector(x_, y_);
}
};
class BoxData
{
public:
const double Len = 1.;
const double LenHalf = 0.5 * Len;
long double d = 1. / 14; // d is the distance between each atom
in the initial trigonal lattice
int nu = 7; // auxillary parameter - will be varied
long double d0 = d * (1 - 2^(nu - 8)); // cutoff distance
double alpha = d - d0; // maximum allowed displacement
};
int main() {
// Initialize box
LoadBox();
// Institute a for loop here
SystemEnergy();
MonteCarloMove();
return 0;
}
//Putting atoms into box
void LoadBox()
{
ofstream myfile("init.dat", ios::out);
//Load atoms in box in triangular offset lattice
const double x_shift = 1. / 14;
const double y_shift = 1. / 16;
double x = 0;
double y = 0;
double x_offset = 0;
for (y = 0; y <= 1. - y_shift; y += y_shift) {
for (x = x_offset; x < 0.99; x += x_shift) {
// create atom in position (x, y)
// and store it in array of atoms
atoms.push_back(Atom(x, y));
}
// every new row flip offset 0 -> 1/28 -> 0 -> 1/28...
if (x_offset < x_shift / 4) {
x_offset = x_shift / 2;
} else {
x_offset = 0.0;
}
}
const int numAtoms = atoms.size();
//print the position of each atom in the file init.dat
for (int i = 0; i < numAtoms; i++) {
myfile << "x is " << atoms[i].pos.x << " y is " << atoms[i].pos.y << endl;
}
myfile.close();
}
Part 2 : Energy calculation
vector<Atom> atoms;
BoxData box_;
void SystemEnergy()
{
ofstream myfile("energy.dat", ios::out);
double box_Len, box_LenHalf, box_d0;
double dij; // distance between two atoms
double Uij; // energy between two particles
double UTotal = 0;
double pbcx, pbcy; // pbc -> periodic boundary condition
double dx, dy;
myfile << "d0 is " << box_d0 << endl;
// define the number of atoms as the size of the array of atoms
const int numAtoms = atoms.size();
//pick atoms
for (int i=0; i<numAtoms-1; i++) { // pick one atom -> "Atom a"
Atom &a = atoms[i];
for (int j=i+1; j<numAtoms; j++) { // pick another atom -> "Atom b"
Atom &b = atoms[j];
dx = a.pos.x - b.pos.x;
dy = a.pos.y - b.pos.y;
pbcx = 0.0;
pbcy = 0.0;
// enforce periodic boundary conditions
if(dx > box_LenHalf) pbcx =- box_Len;
if(dx < -box_LenHalf) pbcx =+ box_Len;
if(dy > box_LenHalf) pbcy =- box_Len;
if(dy < -box_LenHalf) pbcy =+ box_Len;
dx += pbcx;
dy += pbcy;
// calculate distance between atoms
dij = sqrt(dx*dx + dy*dy);
// compare dij to the cutoff distance to determine energy
if (dij > box_d0) {
Uij = 0;
} else {
Uij = 1;
}
myfile << "i is " << i << " j is " << j << " dij is " << dij << " d0 is " << box_d0 << " Uij is " << Uij << endl;
UTotal += Uij; // sum the energies
}
}
myfile << "Energy of the system is " << UTotal << endl;
myfile.close();
}
Sorry for the formatting issues - getting the hang of copy/pasting to the forum.
I wrote the code in C++ which solves the time-dependent 1D Schrodinger equation for the anharmonic potential V = x^2/2 + lambda*x^4, using Thomas algorithm. My code is working and I animate the results in Mathematica, to check what is going on. I test the code against the known solution for the harmonic potential (I put lambda = 0), but the animation shows that abs(Psi) is changing with time, and I know that is not correct for the harmonic potential. Actually, I see that in one point it time it becomes constant, but before that is oscillating.
So I understand that I need to have constant magnitude of the wave function over the time interval, but I don't know how to do it, or where am I doing mistake.
Here is my code and the animation for 100 time steps and 100 points on the grid.
#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>
#include <cstdlib>
#include <complex>
#include <fstream>
using namespace std;
// Mandatory parameters
const int L = 1; //length of domain in x direction
const int tmax = 10; //end time
const int nx = 100, nt = 100; //number of the grid points and time steps respectively
double lambda; //dictates the shape of the potential (we can use lambda = 0.0
// to test the code against the known solution for the harmonic
// oscillator)
complex<double> I(0.0, 1.0); //imaginary unit
// Derived parameters
double delta_x = 1. / (nx - 1);
//spacing between the grid points
double delta_t = 1. / (nt - 1);
//the time step
double r = delta_t / (delta_x * delta_x); //used to simplify expressions for
// the coefficients of the lhs and
// rhs of the matrix eqn
// Algorithm for solving the tridiagonal matrix system
vector<complex<double> > thomas_algorithm(vector<double>& a,
vector<complex<double> >& b,
vector<double>& c,
vector<complex<double> >& d)
{
// Temporary wave function
vector<complex<double> > y(nx + 1, 0.0);
// Modified matrix coefficients
vector<complex<double> > c_prime(nx + 1, 0.0);
vector<complex<double> > d_prime(nx + 1, 0.0);
// This updates the coefficients in the first row
c_prime[0] = c[0] / b[0];
d_prime[0] = d[0] / b[0];
// Create the c_prime and d_prime coefficients in the forward sweep
for (int i = 1; i < nx + 1; i++)
{
complex<double> m = 1.0 / (b[i] - a[i] * c_prime[i - 1]);
c_prime[i] = c[i] * m;
d_prime[i] = (d[i] - a[i] * d_prime[i - 1]) * m;
}
// This gives the value of the last equation in the system
y[nx] = d_prime[nx];
// This is the reverse sweep, used to update the solution vector
for (int i = nx - 1; i > 0; i--)
{
y[i] = d_prime[i] - c_prime[i] * y[i + 1];
}
return y;
}
void calc()
{
// First create the vectors to store the coefficients
vector<double> a(nx + 1, 1.0);
vector<complex<double> > b(nx + 1, 0.0);
vector<double> c(nx + 1, 1.0);
vector<complex<double> > d(nx + 1, 0.0);
vector<complex<double> > psi(nx + 1, 0.0);
vector<complex<double> > phi(nx + 1, 0.0);
vector<double> V(nx + 1, 0.0);
vector<double> x(nx + 1, 0);
vector<vector<complex<double> > > PSI(nt + 1,
vector<complex<double> >(nx + 1,
0.0));
vector<double> prob(nx + 1, 0);
// We don't have the first member of the left diagonal and the last member
// of the right diagonal
a[0] = 0.0;
c[nx] = 0.0;
for (int i = 0; i < nx + 1; i++)
{
x[i] = (-nx / 2) + i; // Values on the x axis
// Eigenfunction of the harmonic oscillator in the ground state
phi[i] = exp(-pow(x[i] * delta_x, 2) / 2) / (pow(M_PI, 0.25));
// Anharmonic potential
V[i] = pow(x[i] * delta_x, 2) / 2 + lambda * pow(x[i] * delta_x, 4);
// The main diagonal coefficients
b[i] = 2.0 * I / r - 2.0 + V[i] * delta_x * delta_x;
}
double sum0 = 0.0;
for (int i = 0; i < nx + 1; i++)
{
PSI[0][i] = phi[i]; // Initial condition for the wave function
sum0 += abs(pow(PSI[0][i], 2)); // Needed for the normalization
}
sum0 = sum0 * delta_x;
for (int i = 0; i < nx + 1; i++)
{
PSI[0][i] = PSI[0][i] / sqrt(sum0); // Normalization of the initial
// wave function
}
for (int j = 0; j < nt; j++)
{
PSI[j][0] = 0.0;
PSI[j][nx] = 0.0; // Boundary conditions for the wave function
d[0] = 0.0;
d[nx] = 0.0; // Boundary conditions for the rhs
// Fill in the current time step vector d representing the rhs
for (int i = 1; i < nx + 1; i++)
{
d[i] = PSI[j][i + 1]
+ (2.0 - 2.0 * I / r - V[i] * delta_x * delta_x) * PSI[j][i]
+ PSI[j][i - 1];
}
// Now solve the tridiagonal system
psi = thomas_algorithm(a, b, c, d);
for (int i = 1; i < nx; i++)
{
PSI[j + 1][i] = psi[i]; // Assign values to the wave function
}
for (int i = 0; i < nx + 1; i++)
{
// Probability density of the wave function in the next time step
prob[i] = abs(PSI[j + 1][i] * conj(PSI[j + 1][i]));
}
double sum = 0.0;
for (int i = 0; i < nx + 1; i++)
{
sum += prob[i] * delta_x;
}
for (int i = 0; i < nx + 1; i++)
{
// Normalization of the wave function in the next time step
PSI[j + 1][i] /= sqrt(sum);
}
}
// Opening files for writing the results
ofstream file_psi_re, file_psi_imag, file_psi_abs, file_potential,
file_phi0;
file_psi_re.open("psi_re.dat");
file_psi_imag.open("psi_imag.dat");
file_psi_abs.open("psi_abs.dat");
for (int i = 0; i < nx + 1; i++)
{
file_psi_re << fixed << x[i] << " ";
file_psi_imag << fixed << x[i] << " ";
file_psi_abs << fixed << x[i] << " ";
for (int j = 0; j < nt + 1; j++)
{
file_psi_re << fixed << setprecision(6) << PSI[j][i].real() << " ";
file_psi_imag << fixed << setprecision(6) << PSI[j][i].imag()
<< " ";
file_psi_abs << fixed << setprecision(6) << abs(PSI[j][i]) << " ";
}
file_psi_re << endl;
file_psi_imag << endl;
file_psi_abs << endl;
}
}
int main(int argc, char **argv)
{
calc();
return 0;
}
The black line is abs(psi), the red one is Im(psi) and the blue one is Re(psi).
(Bear in mind that my computational physics course was ten years ago now)
You say you are solving a time-dependent system, but I don't see any time-dependence (even if lambda != 0). In the Schrodinger Equation, if the potential function does not depend on time then the different equation is called separable because you can solve the time component and spatial component of the differential equation separately.
The general solution in that case is just the solution to the time-independent Schrodinger Equation multiplied by exp(-iE/h_bar). When you plot the magnitude of the probability that term just becomes 1 and so the probability doesn't change over time. In these cases people quite typically just ignore the time component altogether.
All this is to say that since your potential function doesn't depend on time then you aren't solving a time-dependent Schrodinger Equation. The Tridiagonal Matrix Algorithm can only be used to solve ordinary differential equations, whereas if your potential depended on time you would have a partial differential equation and would need a different method to solve it. Also as a result of that plotting the probability density over time is rarely interesting.
As for why your potential is not constant, numerical methods for finding eigenvalues and eigenvectors rarely produce the normalised eigenvectors naturally, so are you manually normalising your eigenvector before computing your probabilities?
I'm trying to write a simple MD program in C/C++ (I'm used to C but I'm trying to learning C++, so my code is a little "mix"... I know that this is suboptimal and I will move to full C++ as soon as I fully understand it).
Everything seems to run but I have divergences in Kinetic energy, the system does not thermalize and temperature (prop to K) goes from order(10°K) to order(10000°K) in a single step.
I'm working with a low time-step of 0.002 (total time of simulation: 30) so I should not have this enormous error...
This is my code, if something is not clear I can try to explain it better
int main(){
...
int n, t, m, i;
double r, K, U, E,P, totalE, temperature, d, x,y,z, temp;
...
double data[5][PARTICELLE], vel[3][PARTICELLE],dataNew[3][PARTICELLE]; //0,1,2 are x,y,z. 3, 4 for data are Energy and Pressure
double force[3][PARTICELLE], forceNew[3][PARTICELLE];
double velQ[PARTICELLE]; //square velocity
ofstream out(OUTDATA);
//inizio MD
for(t=0; t<PASSI; t++){
//inizialization
K=0;
U=0;
E=0;
P=0;
fill(data[3], data[3]+PARTICELLE, 0); //E=0 for each particle
fill(data[4], data[4]+PARTICELLE, 0);
fill(velQ, velQ+PARTICELLE, 0);
for(i=0; i<3; i++){
fill(force[i], force[i]+PARTICELLE, 0);
fill(forceNew[i], forceNew[i]+PARTICELLE, 0);
}
for(n=0; n<PARTICELLE; n++) { //for on the n_ particle. A step is a move of n=PARTICELLE particles
for (i = 0; i < 3; i++) { //compute vSquare
velQ[n] += vel[i][n] * vel[i][n];
}
K += 0.5 * MASSA * velQ[n]; //compute Kinetic Energy
for(m=0; m<PARTICELLE; m++){ //loop on m!=n to compute F, E, P
if(m!=n){
r=0;
for(i=0; i<3; i++){ //calculation of radius and x,y,z
d = data[i][m] - data[i][n];
d = d - (NINT(d / LATO) * LATO);
if(i==0)x=d;
if(i==1)y=d;
if(i==2)z=d;
r += d * d;
}
//if (t<2) cout << "x y z" << x << " " << y << " " << z << endl;
r=sqrt(r);
if (r < R) {
data[3][n] += energy(r); //update Energy of n
for(i=0; i<3; i++){
if(i==0)temp=x;
if(i==1)temp=y;
if(i==2)temp=z;
force[i][n]+=forza(r,temp); //compute force (cartesian components)
//if(t<2)cout << "force " <<n << " " << m << " "<< force[i][n] << endl;
}
if (m < n)data[4][n] += (-energy(r) * (1 + r)); //pressure
}
}
}
U+=data[3][n]; //total potential energy
P+=data[4][n]; //total pressure
for (i = 0; i < 3; i++) { //Verlet update, part 1
dataNew[i][n] = data[i][n] + vel[i][n] * DeltaT + 0.5 * force[i][n] * DeltaT * DeltaT / MASSA;
}
for(m=0; m<PARTICELLE; m++){ //update force
if(m!=n){
r=0;
for(i=0; i<3; i++){
d = data[i][m] - dataNew[i][n];
d = d - (NINT(d / LATO) * LATO);
if(i==0)x=d;
if(i==1)y=d;
if(i==2)z=d;
r += d * d;
}
r=sqrt(r);
if (r < R) {
for(i=0; i<3; i++) {
if (i == 0)temp = x;
if (i == 1)temp = y;
if (i == 2)temp = z;
forceNew[i][n] += forza(r, temp);
}
}
}
}
for(i=0; i<3; i++){ //new position and Verlet part 2
data[i][n]=dataNew[i][n];
vel[i][n]=vel[i][n] + DeltaT * 0.5*(forceNew[i][n] + force[i][n]) / MASSA;
}
}
totalE=U+K; //total energy
temperature = 2*K/(PARTICELLE*3);
out << t*DeltaT << " " << U << " " << P << " " << totalE << " " << temperature << endl;
}
out.close();
return 0;
}
where my system is under a potential e^-r/r, so I have:
double energy( double r){
return (A*SIGMA*exp(-r/SIGMA)/r);
}
double forza(double r, double h){ //h is for x,y,z
double bubba;
bubba= (A*SIGMA*(exp(-r)*h*(r+1)/(r*r*r)));
return bubba;
}
Thanks for any help. I'm working on this code since April and still I have no solution...
edit: to be clearer: CAPITAL terms and DeltaT are values defined in DEFINE
To preface this: I'm currently a first-year student who was allowed to enroll in some second-year classes. Because of this, I'm currently wrangling a language (C++) that I haven't really had the time to learn (First-years mostly learn C#), so this code might not be pretty.
Our assignment is twofold. First, we need to write a program that outputs a Mandelbrot image in a PPM. To achieve this, I've followed a Youtube tutorial here.
The second part of the assignment is to make the program multithreaded. Essentially, the program is supposed to use 4 threads that each draw a quarter of the image.
To this end I have altered the code from the video tutorial, and converted the main to a method. Now, I'm trying to properly make the first quarter of the image. I figured the way to do this was to adjust
for (int y = 0; y < imageHeight; y++) //Rows!
{
for (int x = 0; x < imageWidth; x++) //Columns! (pixels in every row)
{
to
for (int y = 0; y < halfHeight; y++) //Rows!
{
for (int x = 0; x < halfWidth; x++) //Columns! (pixels in every row)
{
However, instead of drawing the top left quarter as I suspected, the program drew along the full width, repeating itself after the halfway mark of the image width was reached, and only drew along a quarter of the height
(see image)
As I like to learn from my mistakes, I'd love to know what exactly is going wrong here.
Thank you for helping a programming greenhorn out :)
Full program code below.
#include "stdafx.h"
#include <fstream>
#include <iostream>
int imageWidth = 512, imageHeight = 512, maxN = 255, halfWidth = 256, halfHeight = 256;
double minR = -1.5, maxR = 0.7, minI = -1.0, maxI = 1.0;
std::ofstream f_out("output_image.ppm");
int findMandelbrot(double cr, double ci, int max_iterations)
{
int i = 0;
double zr = 0.0, zi = 0.0;
while (i < max_iterations && zr * zr + zi * zi < 4.0)
{
double temp = zr * zr - zi * zi + cr;
zi = 2.0 * zr * zi + ci;
zr = temp;
i++;
}
return i;
}
double mapToReal(int x, int imageWidth, double minR, double maxR)
{
double range = maxR - minR;
return x * (range / imageWidth) + minR;
}
double mapToImaginary(int y, int imageHeight, double minI, double maxI)
{
double range = maxI - minI;
return y * (range / imageHeight) + minI;
}
void threadedMandelbrot()
{
for (int y = 0; y < halfHeight; y++) //Rows!
{
for (int x = 0; x < halfWidth; x++) //Columns! (pixels in every row)
{
//... Find the real and imaginary values of c, corresponding
// to that x,y pixel in the image
double cr = mapToReal(x, imageWidth, minR, maxR);
double ci = mapToImaginary(y, imageHeight, minI, maxI);
//... Find the number of iterations in the Mandelbrot formula
// using said c.
int n = findMandelbrot(cr, ci, maxN);
//... Map the resulting number to an RGB value.
int r = (n % 256);
int g = (n % 256);
int b = (n % 256);
//... Output it to the image
f_out << r << " " << g << " " << b << " ";
}
f_out << std::endl;
}
}
int main()
{
//Initializes file
f_out << "P3" << std::endl;
f_out << imageWidth << " " << imageHeight << std::endl;
f_out << "256" << std::endl;
//For every pixel...
threadedMandelbrot();
f_out.close();
std::cout << "Helemaal klaar!" << std::endl;
return 0;
}
Your are calculating only a quarter of the image, so you have to set the dimension of that to halfHeight, halfWidth or fill the file with zeroes. When the image viewer reads the file, it shows two lines of it in a single line of pixels untill it reaches the end of the file, at a quarter of the picture height.
To fix the problem you just have to calculate the other three quarters of the image, but I suggest you to seperate the calc function from the file writing function: do the threaded calcs putting the result in an array (std::array or std::vector), look up the right color and then write to file.
In my code, I'm trying to prevent circles from overlapping so I specified it as a condition on the distance between the centres of the circles but it seems to not work all the time
as you can see :
could it be some kind of numerical precision rounding problem ?
Here is the relevant code (I can post the whole code if needed):
const double win_size = 800;
const double L = 50e-9; //box size (m)
const double k = 1.38e-23; // Boltzmann constant = 1.38e-23 J/K
const double R = 1.6e-10*30; //N2 radius = 1.6e-10 m
const double m = 4.65e-26; //N2 mass = 4.65e-26 kg
struct parameters{
double x;
double y;
double v_x;
double v_y;
};
bool empty_space(double x, double y, struct parameters gas[], int N, int i){
if (i == 0) return true;
for (int i = 0; i<N; i++){
if (pow(x-gas[i].x,2) + pow(y-gas[i].y,2) <= 4*R*R){
cout << gas[i].x << " " << gas[i].y << endl;
return false;
}
}
return true;
}
void initialize(struct parameters gas[], int N, double T){ // Sets initial conditions (velocity depends on temperature)
int tries = 0;
double x, y;
for (int i=0; i<N; i++){
if (tries == 10000){
cout << "Couldn't fit " << N << " molecules in the box, aborting simulation... " << endl;
exit(1);
}
x = R + (L - 2*R)*rand()/RAND_MAX;
y = R + (L - 2*R)*rand()/RAND_MAX;
if (empty_space(x,y,gas,N,i)){
gas[i].x = x;
gas[i].y = y;
}
else {
i--;
tries++;
}
gas[i].v_x = sqrt(2*k*T/m)*(1-2.0*rand()/RAND_MAX);
gas[i].v_y = (2*(rand()%2) - 1)*sqrt(2*k*T/m - pow(gas[i].v_x, 2));
}
}
void draw(int window, struct parameters gas[], int N, int automatic){
g2_pen(window,g2_ink(window,0.8,0.3,0.4));
for (int i=0; i<N; i++){
g2_circle(window,gas[i].x*win_size/L,gas[i].y*win_size/L,R*win_size/L);
}
g2_flush(window);
usleep(10000);
g2_pen(window,0);
g2_filled_rectangle(window,0,0,win_size,win_size);
if (!automatic) getchar();
}
The first debugging step is to print the coordinates of the circles that have clashed somehow, then see what the "distance" function is returning for their centers. My guess it it's somehow a rounding problem but this seems to be what you need to do next.