// Update the pos of the given virtual particle as defined by the real // particles in the same molecule void update_mol_pos_particle(Particle *p) { // First obtain the real particle responsible for this virtual particle: // Find the 1st real particle in the topology for the virtual particle's mol_id Particle *p_real = vs_relative_get_real_particle(p); // Check, if a real particle was found if (!p_real) { printf(stderr,"virtual_sites_relative.c - update_mol_pos_particle(): No real particle associated with virtual site.\n"); return; } // Calculate the quaternion defining the orientation of the vecotr connectinhg // the virtual site and the real particle // This is obtained, by multiplying the quaternion representing the director // of the real particle with the quaternion of the virtual particle, which // specifies the relative orientation. double q[4]; multiply_quaternions(p_real->r.quat,p->r.quat,q); // Calculate the director resulting from the quaternions double director[3]; convert_quat_to_quatu(q,director); // normalize double l =sqrt(sqrlen(director)); // Division comes in the loop below // Calculate the new position of the virtual sites from // position of real particle + director int i; double new_pos[3]; double tmp; for (i=0;i<3;i++) { new_pos[i] =p_real->r.p[i] +director[i]/l*p->p.vs_relative_distance; // Handle the case that one of the particles had gone over the periodic // boundary and its coordinate has been folded #ifdef PARTIAL_PERIODIC if (PERIODIC(i)) #endif { tmp =p->r.p[i] -new_pos[i]; //printf("%f\n",tmp); if (tmp > box_l[i]/2.) { //printf("greater than box_l/2 %f\n",tmp); p->r.p[i] =new_pos[i] + box_l[i]; } else if (tmp < -box_l[i]/2.) { //printf("smaller than box_l/2 %f\n",tmp); p->r.p[i] =new_pos[i] - box_l[i]; } else p->r.p[i] =new_pos[i]; } #ifdef PARTIAL_PERIODIC else p->r.p[i] =new_pos[i]; #endif } }
/** propagate angular velocities and quaternions \todo implement for fixed_coord_flag */ void propagate_omega_quat() { Particle *p; Cell *cell; int c,i,j, np; double lambda, dt2, dt4, dtdt, dtdt2; dt2 = time_step*0.5; dt4 = time_step*0.25; dtdt = time_step*time_step; dtdt2 = dtdt*0.5; INTEG_TRACE(fprintf(stderr,"%d: propagate_omega_quat:\n",this_node)); for (c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; for(i = 0; i < np; i++) { double Qd[4], Qdd[4], S[3], Wd[3]; #ifdef VIRTUAL_SITES // Virtual sites are not propagated in the integration step if (ifParticleIsVirtual(&p[i])) continue; #endif define_Qdd(&p[i], Qd, Qdd, S, Wd); lambda = 1 - S[0]*dtdt2 - sqrt(1 - dtdt*(S[0] + time_step*(S[1] + dt4*(S[2]-S[0]*S[0])))); for(j=0; j < 3; j++){ p[i].m.omega[j]+= dt2*Wd[j]; } ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: PV_1 v_new = (%.3e,%.3e,%.3e)\n",this_node,p[i].m.v[0],p[i].m.v[1],p[i].m.v[2])); p[i].r.quat[0]+= time_step*(Qd[0] + dt2*Qdd[0]) - lambda*p[i].r.quat[0]; p[i].r.quat[1]+= time_step*(Qd[1] + dt2*Qdd[1]) - lambda*p[i].r.quat[1]; p[i].r.quat[2]+= time_step*(Qd[2] + dt2*Qdd[2]) - lambda*p[i].r.quat[2]; p[i].r.quat[3]+= time_step*(Qd[3] + dt2*Qdd[3]) - lambda*p[i].r.quat[3]; // Update the director convert_quat_to_quatu(p[i].r.quat, p[i].r.quatu); #ifdef DIPOLES // When dipoles are enabled, update dipole moment convert_quatu_to_dip(p[i].r.quatu, p[i].p.dipm, p[i].r.dip); #endif ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: PPOS p = (%.3f,%.3f,%.3f)\n",this_node,p[i].r.p[0],p[i].r.p[1],p[i].r.p[2])); } } }
/** Rotate the particle p around the NORMALIZED axis aSpaceFrame by amount phi */ void rotate_particle(Particle* p, double* aSpaceFrame, double phi) { // Convert rotation axis to body-fixed frame double a[3]; convert_vec_space_to_body(p,aSpaceFrame,a); // Apply restrictions from the rotation_per_particle feature #ifdef ROTATION_PER_PARTICLE // printf("%g %g %g - ",a[0],a[1],a[2]); // Rotation turned off entirely? if (p->p.rotation <2) return; // Per coordinate fixing if (!(p->p.rotation & 2)) a[0]=0; if (!(p->p.rotation & 4)) a[1]=0; if (!(p->p.rotation & 8)) a[2]=0; // Re-normalize rotation axis double l=sqrt(sqrlen(a)); // Check, if the rotation axis is nonzero if (l<1E-10) return; for (int i=0;i<3;i++) a[i]/=l; // printf("%g %g %g\n",a[0],a[1],a[2]); #endif double q[4]; q[0]=cos(phi/2); double tmp=sin(phi/2); q[1]=tmp*a[0]; q[2]=tmp*a[1]; q[3]=tmp*a[2]; // Normalize normalize_quaternion(q); // Rotate the particle double qn[4]; // Resulting quaternion multiply_quaternions(p->r.quat,q,qn); for (int k=0; k<4; k++) p->r.quat[k]=qn[k]; convert_quat_to_quatu(p->r.quat, p->r.quatu); #ifdef DIPOLES // When dipoles are enabled, update dipole moment convert_quatu_to_dip(p->r.quatu, p->p.dipm, p->r.dip); #endif }
// Update the vel of the given virtual particle as defined by the real // particles in the same molecule void update_mol_vel_particle(Particle *p) { // NOT TESTED! // First obtain the real particle responsible for this virtual particle: Particle *p_real = vs_relative_get_real_particle(p); // Check, if a real particle was found if (!p_real) { char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "virtual_sites_relative.cpp - update_mol_pos_particle(): No real particle associated with virtual site.\n"); return; } // Calculate the quaternion defining the orientation of the vecotr connectinhg // the virtual site and the real particle // This is obtained, by multiplying the quaternion representing the director // of the real particle with the quaternion of the virtual particle, which // specifies the relative orientation. double q[4]; multiply_quaternions(p_real->r.quat,p->r.quat,q); // Calculate the director resulting from the quaternions double director[3]; convert_quat_to_quatu(q,director); // normalize double l =sqrt(sqrlen(director)); // Division comes in the loop below // Get omega of real particle in space-fixed frame double omega_space_frame[3]; convert_omega_body_to_space(p_real,omega_space_frame); // Obtain velocity from v=v_real particle + omega_real_particle \times director vector_product(omega_space_frame,director,p->m.v); int i; // Add prefactors and add velocity of real particle for (i=0;i<3;i++) { // Scale the velocity by the distance of virtual particle from the real particle // Also, espresso stores not velocity but velocity * time_step p->m.v[i] *= time_step * p->p.vs_relative_distance/l; // Add velocity of real particle p->m.v[i] += p_real->m.v[i]; } }