+ return moldyn->virial;
+}
+
+double pressure_calc(t_moldyn *moldyn) {
+
+ /*
+ * PV = NkT + <W>
+ * with W = 1/3 sum_i f_i r_i (- skipped!)
+ * virial = sum_i f_i r_i
+ *
+ * => P = (2 Ekin + virial) / (3V)
+ */
+
+ /* assume up to date virial & up to date kinetic energy */
+
+ /* pressure (atom virials) */
+ moldyn->p=2.0*moldyn->ekin+moldyn->virial;
+ moldyn->p/=(3.0*moldyn->volume);
+
+ /* pressure (absolute coordinates) */
+ moldyn->gp=2.0*moldyn->ekin+moldyn->gv;
+ moldyn->gp/=(3.0*moldyn->volume);
+
+ return moldyn->p;
+}
+
+int average_reset(t_moldyn *moldyn) {
+
+ printf("[moldyn] average reset\n");
+
+ /* update skip value */
+ moldyn->avg_skip=moldyn->total_steps;
+
+ /* kinetic energy */
+ moldyn->k_sum=0.0;
+ moldyn->k2_sum=0.0;
+
+ /* potential energy */
+ moldyn->v_sum=0.0;
+ moldyn->v2_sum=0.0;
+
+ /* temperature */
+ moldyn->t_sum=0.0;
+
+ /* virial */
+ moldyn->virial_sum=0.0;
+ moldyn->gv_sum=0.0;
+
+ /* pressure */
+ moldyn->p_sum=0.0;
+ moldyn->gp_sum=0.0;
+
+ return 0;
+}
+
+int average_and_fluctuation_calc(t_moldyn *moldyn) {
+
+ int denom;
+
+ if(moldyn->total_steps<moldyn->avg_skip)
+ return 0;
+
+ denom=moldyn->total_steps+1-moldyn->avg_skip;
+
+ /* assume up to date energies, temperature, pressure etc */
+
+ /* kinetic energy */
+ moldyn->k_sum+=moldyn->ekin;
+ moldyn->k2_sum+=(moldyn->ekin*moldyn->ekin);
+ moldyn->k_avg=moldyn->k_sum/denom;
+ moldyn->k2_avg=moldyn->k2_sum/denom;
+ moldyn->dk2_avg=moldyn->k2_avg-(moldyn->k_avg*moldyn->k_avg);
+
+ /* potential energy */
+ moldyn->v_sum+=moldyn->energy;
+ moldyn->v2_sum+=(moldyn->energy*moldyn->energy);
+ moldyn->v_avg=moldyn->v_sum/denom;
+ moldyn->v2_avg=moldyn->v2_sum/denom;
+ moldyn->dv2_avg=moldyn->v2_avg-(moldyn->v_avg*moldyn->v_avg);
+
+ /* temperature */
+ moldyn->t_sum+=moldyn->t;
+ moldyn->t_avg=moldyn->t_sum/denom;
+
+ /* virial */
+ moldyn->virial_sum+=moldyn->virial;
+ moldyn->virial_avg=moldyn->virial_sum/denom;
+ moldyn->gv_sum+=moldyn->gv;
+ moldyn->gv_avg=moldyn->gv_sum/denom;
+
+ /* pressure */
+ moldyn->p_sum+=moldyn->p;
+ moldyn->p_avg=moldyn->p_sum/denom;
+ moldyn->gp_sum+=moldyn->gp;
+ moldyn->gp_avg=moldyn->gp_sum/denom;
+
+ return 0;
+}
+
+int get_heat_capacity(t_moldyn *moldyn) {
+
+ double temp2,ighc;
+
+ /* averages needed for heat capacity calc */
+ if(moldyn->total_steps<moldyn->avg_skip)
+ return 0;
+
+ /* (temperature average)^2 */
+ temp2=moldyn->t_avg*moldyn->t_avg;
+ printf("[moldyn] specific heat capacity for T=%f K [J/(kg K)]\n",
+ moldyn->t_avg);
+
+ /* ideal gas contribution */
+ ighc=3.0*moldyn->count*K_BOLTZMANN/2.0;
+ printf(" ideal gas contribution: %f\n",
+ ighc/moldyn->mass*KILOGRAM/JOULE);
+
+ /* specific heat for nvt ensemble */
+ moldyn->c_v_nvt=moldyn->dv2_avg/(K_BOLTZMANN*temp2)+ighc;
+ moldyn->c_v_nvt/=moldyn->mass;
+
+ /* specific heat for nve ensemble */
+ moldyn->c_v_nve=ighc/(1.0-(moldyn->dv2_avg/(ighc*K_BOLTZMANN*temp2)));
+ moldyn->c_v_nve/=moldyn->mass;
+
+ printf(" NVE: %f\n",moldyn->c_v_nve*KILOGRAM/JOULE);
+ printf(" NVT: %f\n",moldyn->c_v_nvt*KILOGRAM/JOULE);
+printf(" --> <dV2> sim: %f experimental: %f\n",moldyn->dv2_avg,1.5*moldyn->count*K_B2*moldyn->t_avg*moldyn->t_avg*(1.0-1.5*moldyn->count*K_BOLTZMANN/(700*moldyn->mass*JOULE/KILOGRAM)));
+
+ return 0;
+}
+
+double thermodynamic_pressure_calc(t_moldyn *moldyn) {
+
+ t_3dvec dim;
+ //t_3dvec *tp;
+ double u_up,u_down,dv;
+ double scale,p;
+ t_atom *store;
+
+ /*
+ * dU = - p dV
+ *
+ * => p = - dU/dV
+ *
+ */
+
+ scale=0.00001;
+ dv=8*scale*scale*scale*moldyn->volume;
+
+ store=malloc(moldyn->count*sizeof(t_atom));
+ if(store==NULL) {
+ printf("[moldyn] allocating store mem failed\n");
+ return -1;
+ }
+
+ /* save unscaled potential energy + atom/dim configuration */
+ memcpy(store,moldyn->atom,moldyn->count*sizeof(t_atom));
+ dim=moldyn->dim;
+
+ /* scale up dimension and atom positions */
+ scale_dim(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
+ scale_atoms(moldyn,SCALE_UP,scale,TRUE,TRUE,TRUE);
+ link_cell_shutdown(moldyn);
+ link_cell_init(moldyn,QUIET);
+ potential_force_calc(moldyn);
+ u_up=moldyn->energy;
+
+ /* restore atomic configuration + dim */
+ memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
+ moldyn->dim=dim;
+
+ /* scale down dimension and atom positions */
+ scale_dim(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
+ scale_atoms(moldyn,SCALE_DOWN,scale,TRUE,TRUE,TRUE);
+ link_cell_shutdown(moldyn);
+ link_cell_init(moldyn,QUIET);
+ potential_force_calc(moldyn);
+ u_down=moldyn->energy;
+
+ /* calculate pressure */
+ p=-(u_up-u_down)/dv;
+printf("-------> %.10f %.10f %f\n",u_up/EV/moldyn->count,u_down/EV/moldyn->count,p/BAR);
+
+ /* restore atomic configuration + dim */
+ memcpy(moldyn->atom,store,moldyn->count*sizeof(t_atom));
+ moldyn->dim=dim;
+
+ /* restore energy */
+ potential_force_calc(moldyn);
+
+ link_cell_shutdown(moldyn);
+ link_cell_init(moldyn,QUIET);
+
+ return p;