// 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) { 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 // 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 // fold_coordinate(p->r.p,p->l.i,i); } }
void rotate_point_axis(point_3D &point, double angle, point_3D axis) { double q1[4], q2[4], q3[4], q4[4]; // quaternions double cos_angle, sin_angle; if (angle < 0) { angle *= -1; axis.x *= -1; axis.y *= -1; axis.z *= -1; } q1[0] = 0; q1[1] = point.x; q1[2] = point.y; q1[3] = point.z; cos_angle = cos(angle / 2.0); sin_angle = sin(angle / 2.0); q2[0] = cos_angle; q2[1] = axis.x * sin_angle; q2[2] = axis.y * sin_angle; q2[3] = axis.z * sin_angle; multiply_quaternions(q2,q1,q3); q2[1] *= -1; q2[2] *= -1; q2[3] *= -1; multiply_quaternions(q3,q2,q4); point.x = q4[1]; point.y = q4[2]; point.z = q4[3]; }
/** 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]; } }
// Setup the virtual_sites_relative properties of a particle so that the given virtaul particle will follow the given real particle int vs_relate_to(int part_num, int relate_to) { // Get the data for the particle we act on and the one we wnat to relate // it to. Particle p_current,p_relate_to; if ((get_particle_data(relate_to,&p_relate_to)!=ES_OK) || (get_particle_data(part_num,&p_current)!=ES_OK)) { char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "Could not retrieve particle data for the given id"); return ES_ERROR; } // get teh distance between the particles double d[3]; get_mi_vector(d, p_current.r.p,p_relate_to.r.p); // Set the particle id of the particle we want to relate to and the distnace if (set_particle_vs_relative(part_num, relate_to, sqrt(sqrlen(d))) == ES_ERROR) { char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "setting the vs_relative attributes failed"); return ES_ERROR; } // Check, if the distance between virtual and non-virtual particles is larger htan minimum global cutoff // If so, warn user double l=sqrt(sqrlen(d)); if (l>min_global_cut) { char *errtxt = runtime_error(300 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "Warning: The distance between virtual and non-virtual particle (%f) is\nlarger than the minimum global cutoff (%f). This may lead to incorrect simulations\nunder certain conditions. Use \"setmd min_global_cut\" to increase the minimum cutoff.\n",l,min_global_cut); return ES_ERROR; } // Now, calculate the quaternions which specify the angle between // the director of the particel we relate to and the vector // (paritlce_we_relate_to - this_particle) double quat[4]; // The vs_relative implemnation later obtains the direcotr by multiplying // the quaternions representing the orientation of the real particle // with those in the virtual particle. The re quulting quaternion is then // converted to a director. // Whe have quat_(real particle) *quat_(virtual particle) // = quat_(obtained from desired director) // Resolving this for the quat_(virtaul particle) //Normalize desired director int i; for (i=0;i<3;i++) d[i]/=l; // Obtain quaternions from desired director double quat_director[4]; convert_quatu_to_quat(d, quat_director); // Define quat as described above: double x=0; for (i=0;i<4;i++) x+=p_relate_to.r.quat[i]*p_relate_to.r.quat[i]; quat[0]=0; for (i=0;i<4;i++) quat[0] +=p_relate_to.r.quat[i]*quat_director[i]; quat[1] =-quat_director[0] *p_relate_to.r.quat[1] +quat_director[1] *p_relate_to.r.quat[0] +quat_director[2] *p_relate_to.r.quat[3] -quat_director[3] *p_relate_to.r.quat[2]; quat[2] =p_relate_to.r.quat[1] *quat_director[3] + p_relate_to.r.quat[0] *quat_director[2] - p_relate_to.r.quat[3] *quat_director[1] - p_relate_to.r.quat[2] * quat_director[0]; quat[3] =quat_director[3] *p_relate_to.r.quat[0] - p_relate_to.r.quat[3] *quat_director[0] + p_relate_to.r.quat[2] * quat_director[1] - p_relate_to.r.quat[1] *quat_director[2]; for (i=0;i<4;i++) quat[i]/=x; // Verify result double qtemp[4]; multiply_quaternions(p_relate_to.r.quat,quat,qtemp); for (i=0;i<4;i++) if (fabs(qtemp[i]-quat_director[i])>1E-9) fprintf(stderr, "vs_relate_to: component %d: %f instead of %f\n", i, qtemp[i], quat_director[i]); // Save the quaternions in the particle if (set_particle_quat(part_num, quat) == ES_ERROR) { char *errtxt = runtime_error(128 + 3*ES_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "set particle position first"); return ES_ERROR; } return ES_OK; }
// Setup the virtual_sites_relative properties of a particle so that the given virtaul particle will follow the given real particle int vs_relate_to(int part_num, int relate_to) { // Get the data for the particle we act on and the one we wnat to relate // it to. Particle p_current,p_relate_to; if ((get_particle_data(relate_to,&p_relate_to)!=TCL_OK) || (get_particle_data(part_num,&p_current)!=TCL_OK)) { printf("Could not retrieve particle data for the given id.\n"); return TCL_ERROR; } // get teh distance between the particles double d[3]; get_mi_vector(d, p_current.r.p,p_relate_to.r.p); // Set the particle id of the particle we want to relate to and the distnace if (set_particle_vs_relative(part_num, relate_to, sqrt(sqrlen(d))) == TCL_ERROR) { printf("setting the vs_relative attributes failed.\n"); return TCL_ERROR; } // Now, calculate the quaternions which specify the angle between // the director of the particel we relate to and the vector // (paritlce_we_relate_to - this_particle) double quat[4]; // The vs_relative implemnation later obtains the direcotr by multiplying // the quaternions representing the orientation of the real particle // with those in the virtual particle. The re quulting quaternion is then // converted to a director. // Whe have quat_(real particle) *quat_(virtual particle) // = quat_(obtained from desired director) // Resolving this for the quat_(virtaul particle) //Normalize desired director double l=sqrt(sqrlen(d)); int i; for (i=0;i<3;i++) d[i]/=l; // Obtain quaternions from desired director double quat_director[4]; convert_quatu_to_quat(d, quat_director); // Define quat as described above: double x=0; for (i=0;i<4;i++) x+=p_relate_to.r.quat[i]*p_relate_to.r.quat[i]; quat[0]=0; for (i=0;i<4;i++) quat[0] +=p_relate_to.r.quat[i]*quat_director[i]; quat[1] =-quat_director[0] *p_relate_to.r.quat[1] +quat_director[1] *p_relate_to.r.quat[0] +quat_director[2] *p_relate_to.r.quat[3] -quat_director[3] *p_relate_to.r.quat[2]; quat[2] =p_relate_to.r.quat[1] *quat_director[3] + p_relate_to.r.quat[0] *quat_director[2] - p_relate_to.r.quat[3] *quat_director[1] - p_relate_to.r.quat[2] * quat_director[0]; quat[3] =quat_director[3] *p_relate_to.r.quat[0] - p_relate_to.r.quat[3] *quat_director[0] + p_relate_to.r.quat[2] * quat_director[1] - p_relate_to.r.quat[1] *quat_director[2]; for (i=0;i<4;i++) quat[i]/=x; // Verify result double qtemp[4]; multiply_quaternions(p_relate_to.r.quat,quat,qtemp); for (i=0;i<4;i++) if (fabs(qtemp[i]-quat_director[i])>1E-9) printf("Component %d: %f instead of %f\n",i,qtemp[i],quat_director[i]); // Save the quaternions in the particle if (set_particle_quat(part_num, quat) == TCL_ERROR) { printf("set particle position first\n"); return TCL_ERROR; } return TCL_OK; }