int set_particle_torque_lab(int part, double torque_lab[3]) { int pnode; if (!particle_node) build_particle_node(); if (part < 0 || part > max_seen_particle) return ES_ERROR; pnode = particle_node[part]; if (pnode == -1) return ES_ERROR; /* Internal functions require the body coordinates so we need to convert to these from the lab frame */ double A[9]; double torque[3]; Particle particle; get_particle_data(part, &particle); define_rotation_matrix(&particle, A); torque[0] = A[0 + 3*0]*torque_lab[0] + A[0 + 3*1]*torque_lab[1] + A[0 + 3*2]*torque_lab[2]; torque[1] = A[1 + 3*0]*torque_lab[0] + A[1 + 3*1]*torque_lab[1] + A[1 + 3*2]*torque_lab[2]; torque[2] = A[2 + 3*0]*torque_lab[0] + A[2 + 3*1]*torque_lab[1] + A[2 + 3*2]*torque_lab[2]; mpi_send_torque(pnode, part, torque); return ES_OK; }
void convert_vec_space_to_body(Particle *p, double *v,double* res) { double A[9]; define_rotation_matrix(p, A); res[0] = A[0 + 3*0]*v[0] + A[0 + 3*1]*v[1] + A[0 + 3*2]*v[2]; res[1] = A[1 + 3*0]*v[0] + A[1 + 3*1]*v[1] + A[1 + 3*2]*v[2]; res[2] = A[2 + 3*0]*v[0] + A[2 + 3*1]*v[1] + A[2 + 3*2]*v[2]; }
void convert_vel_space_to_body(Particle *p, double *vel_body) { double A[9]; define_rotation_matrix(p, A); vel_body[0] = A[0 + 3*0]*p->m.v[0] + A[0 + 3*1]*p->m.v[1] + A[0 + 3*2]*p->m.v[2]; vel_body[1] = A[1 + 3*0]*p->m.v[0] + A[1 + 3*1]*p->m.v[1] + A[1 + 3*2]*p->m.v[2]; vel_body[2] = A[2 + 3*0]*p->m.v[0] + A[2 + 3*1]*p->m.v[1] + A[2 + 3*2]*p->m.v[2]; }
void convert_torques_body_to_space(Particle *p, double *torque) { double A[9]; define_rotation_matrix(p, A); torque[0] = A[0 + 3*0]*p->f.torque[0] + A[1 + 3*0]*p->f.torque[1] + A[2 + 3*0]*p->f.torque[2]; torque[1] = A[0 + 3*1]*p->f.torque[0] + A[1 + 3*1]*p->f.torque[1] + A[2 + 3*1]*p->f.torque[2]; torque[2] = A[0 + 3*2]*p->f.torque[0] + A[1 + 3*2]*p->f.torque[1] + A[2 + 3*2]*p->f.torque[2]; }
void convert_omega_body_to_space(Particle *p, double *omega) { double A[9]; define_rotation_matrix(p, A); omega[0] = A[0 + 3*0]*p->m.omega[0] + A[1 + 3*0]*p->m.omega[1] + A[2 + 3*0]*p->m.omega[2]; omega[1] = A[0 + 3*1]*p->m.omega[0] + A[1 + 3*1]*p->m.omega[1] + A[2 + 3*1]*p->m.omega[2]; omega[2] = A[0 + 3*2]*p->m.omega[0] + A[1 + 3*2]*p->m.omega[1] + A[2 + 3*2]*p->m.omega[2]; }
/** convert the torques to the body-fixed frames before the integration loop */ void convert_initial_torques() { Particle *p; Cell *cell; int c,i, np; double tx, ty, tz; INTEG_TRACE(fprintf(stderr,"%d: convert_initial_torques:\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++) { #ifdef ROTATION_PER_PARTICLE if (!p[i].p.rotation) continue; #endif double A[9]; define_rotation_matrix(&p[i], A); tx = A[0 + 3*0]*p[i].f.torque[0] + A[0 + 3*1]*p[i].f.torque[1] + A[0 + 3*2]*p[i].f.torque[2]; ty = A[1 + 3*0]*p[i].f.torque[0] + A[1 + 3*1]*p[i].f.torque[1] + A[1 + 3*2]*p[i].f.torque[2]; tz = A[2 + 3*0]*p[i].f.torque[0] + A[2 + 3*1]*p[i].f.torque[1] + A[2 + 3*2]*p[i].f.torque[2]; if ( thermo_switch & THERMO_LANGEVIN ) { friction_thermo_langevin_rotation(&p[i]); p[i].f.torque[0]+= tx; p[i].f.torque[1]+= ty; p[i].f.torque[2]+= tz; } else { p[i].f.torque[0] = tx; p[i].f.torque[1] = ty; p[i].f.torque[2] = tz; } #ifdef ROTATION_PER_PARTICLE if (!(p[i].p.rotation & 2)) p[i].f.torque[0]=0; if (!(p[i].p.rotation & 4)) p[i].f.torque[1]=0; if (!(p[i].p.rotation & 8)) p[i].f.torque[2]=0; #endif ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: SCAL f = (%.3e,%.3e,%.3e) v_old = (%.3e,%.3e,%.3e)\n",this_node,p[i].f.f[0],p[i].f.f[1],p[i].f.f[2],p[i].m.v[0],p[i].m.v[1],p[i].m.v[2])); } } }
int observable_calc_particle_angular_momentum(observable* self) { double* A = self->last_value; IntList* ids; if (!sortPartCfg()) { char *errtxt = runtime_error(128); ERROR_SPRINTF(errtxt,"{094 could not sort partCfg} "); return -1; } ids=(IntList*) self->container; for ( int i = 0; i<ids->n; i++ ) { if (ids->e[i] >= n_part) return 1; #ifdef ROTATION double RMat[9]; double omega[3]; define_rotation_matrix(&partCfg[ids->e[i]], RMat); omega[0] = RMat[0 + 3*0]*partCfg[ids->e[i]].m.omega[0] + RMat[1 + 3*0]*partCfg[ids->e[i]].m.omega[1] + RMat[2 + 3*0]*partCfg[ids->e[i]].m.omega[2]; omega[1] = RMat[0 + 3*1]*partCfg[ids->e[i]].m.omega[0] + RMat[1 + 3*1]*partCfg[ids->e[i]].m.omega[1] + RMat[2 + 3*1]*partCfg[ids->e[i]].m.omega[2]; omega[2] = RMat[0 + 3*2]*partCfg[ids->e[i]].m.omega[0] + RMat[1 + 3*2]*partCfg[ids->e[i]].m.omega[1] + RMat[2 + 3*2]*partCfg[ids->e[i]].m.omega[2]; A[3*i + 0] = omega[0]; A[3*i + 1] = omega[1]; A[3*i + 2] = omega[2]; #else A[3*i + 0] = 0.0; A[3*i + 1] = 0.0; A[3*i + 2] = 0.0; #endif } return 0; }
/** convert the torques to the body-fixed frames and propagate angular velocities */ void convert_torques_propagate_omega() { Particle *p; Cell *cell; int c,i, np, times; double dt2, tx, ty, tz; dt2 = time_step*0.5; INTEG_TRACE(fprintf(stderr,"%d: convert_torques_propagate_omega:\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 A[9]; define_rotation_matrix(&p[i], A); tx = A[0 + 3*0]*p[i].f.torque[0] + A[0 + 3*1]*p[i].f.torque[1] + A[0 + 3*2]*p[i].f.torque[2]; ty = A[1 + 3*0]*p[i].f.torque[0] + A[1 + 3*1]*p[i].f.torque[1] + A[1 + 3*2]*p[i].f.torque[2]; tz = A[2 + 3*0]*p[i].f.torque[0] + A[2 + 3*1]*p[i].f.torque[1] + A[2 + 3*2]*p[i].f.torque[2]; if ( thermo_switch & THERMO_LANGEVIN ) { #ifdef THERMOSTAT_IGNORE_NON_VIRTUAL if (!ifParticleIsVirtual(&p[i])) #endif { friction_thermo_langevin_rotation(&p[i]); p[i].f.torque[0]+= tx; p[i].f.torque[1]+= ty; p[i].f.torque[2]+= tz; } } else { p[i].f.torque[0] = tx; p[i].f.torque[1] = ty; p[i].f.torque[2] = tz; } ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: SCAL f = (%.3e,%.3e,%.3e) v_old = (%.3e,%.3e,%.3e)\n",this_node,p[i].f.f[0],p[i].f.f[1],p[i].f.f[2],p[i].m.v[0],p[i].m.v[1],p[i].m.v[2])); #ifdef ROTATIONAL_INERTIA p[i].m.omega[0]+= dt2*p[i].f.torque[0]/p[i].p.rinertia[0]/I[0]; p[i].m.omega[1]+= dt2*p[i].f.torque[1]/p[i].p.rinertia[1]/I[1]; p[i].m.omega[2]+= dt2*p[i].f.torque[2]/p[i].p.rinertia[2]/I[2]; #else p[i].m.omega[0]+= dt2*p[i].f.torque[0]/I[0]; p[i].m.omega[1]+= dt2*p[i].f.torque[1]/I[1]; p[i].m.omega[2]+= dt2*p[i].f.torque[2]/I[2]; #endif /* if the tensor of inertia is isotrpic, the following refinement is not needed. Otherwise repeat this loop 2-3 times depending on the required accuracy */ for(times=0;times<=5;times++) { double Wd[3]; #ifdef ROTATIONAL_INERTIA Wd[0] = (p[i].m.omega[1]*p[i].m.omega[2]*(I[1]-I[2]))/I[0]/p[i].p.rinertia[0]; Wd[1] = (p[i].m.omega[2]*p[i].m.omega[0]*(I[2]-I[0]))/I[1]/p[i].p.rinertia[1]; Wd[2] = (p[i].m.omega[0]*p[i].m.omega[1]*(I[0]-I[1]))/I[2]/p[i].p.rinertia[2]; #else Wd[0] = (p[i].m.omega[1]*p[i].m.omega[2]*(I[1]-I[2]))/I[0]; Wd[1] = (p[i].m.omega[2]*p[i].m.omega[0]*(I[2]-I[0]))/I[1]; Wd[2] = (p[i].m.omega[0]*p[i].m.omega[1]*(I[0]-I[1]))/I[2]; #endif p[i].m.omega[0]+= dt2*Wd[0]; p[i].m.omega[1]+= dt2*Wd[1]; p[i].m.omega[2]+= dt2*Wd[2]; } ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: PV_2 v_new = (%.3e,%.3e,%.3e)\n",this_node,p[i].m.v[0],p[i].m.v[1],p[i].m.v[2])); } } }
/** convert the torques to the body-fixed frames and propagate angular velocities */ void convert_torques_propagate_omega() { Particle *p; Cell *cell; int np; double tx, ty, tz; INTEG_TRACE(fprintf(stderr,"%d: convert_torques_propagate_omega:\n",this_node)); #if defined(LB_GPU) && defined(ENGINE) if (lattice_switch & LATTICE_LB_GPU) { copy_v_cs_from_GPU(); } #endif for (int c = 0; c < local_cells.n; c++) { cell = local_cells.cell[c]; p = cell->part; np = cell->n; for(int i = 0; i < np; i++) { #ifdef ROTATION_PER_PARTICLE if (!p[i].p.rotation) continue; #endif double A[9]; define_rotation_matrix(&p[i], A); tx = A[0 + 3*0]*p[i].f.torque[0] + A[0 + 3*1]*p[i].f.torque[1] + A[0 + 3*2]*p[i].f.torque[2]; ty = A[1 + 3*0]*p[i].f.torque[0] + A[1 + 3*1]*p[i].f.torque[1] + A[1 + 3*2]*p[i].f.torque[2]; tz = A[2 + 3*0]*p[i].f.torque[0] + A[2 + 3*1]*p[i].f.torque[1] + A[2 + 3*2]*p[i].f.torque[2]; if ( thermo_switch & THERMO_LANGEVIN ) { #if defined (VIRTUAL_SITES) && defined(THERMOSTAT_IGNORE_NON_VIRTUAL) if (!ifParticleIsVirtual(&p[i])) #endif { friction_thermo_langevin_rotation(&p[i]); p[i].f.torque[0]+= tx; p[i].f.torque[1]+= ty; p[i].f.torque[2]+= tz; } } else { p[i].f.torque[0] = tx; p[i].f.torque[1] = ty; p[i].f.torque[2] = tz; } #ifdef ROTATION_PER_PARTICLE if (!(p[i].p.rotation & 2)) p[i].f.torque[0]=0; if (!(p[i].p.rotation & 4)) p[i].f.torque[1]=0; if (!(p[i].p.rotation & 8)) p[i].f.torque[2]=0; #endif #if defined(ENGINE) && (defined(LB) || defined(LB_GPU)) double omega_swim[3] = {0, 0, 0}; double omega_swim_body[3] = {0, 0, 0}; if ( p[i].swim.swimming && lattice_switch != 0 ) { double dip[3]; double diff[3]; double cross[3]; double l_diff, l_cross; dip[0] = p[i].swim.dipole_length * p[i].r.quatu[0]; dip[1] = p[i].swim.dipole_length * p[i].r.quatu[1]; dip[2] = p[i].swim.dipole_length * p[i].r.quatu[2]; diff[0] = ( p[i].swim.v_center[0] - p[i].swim.v_source[0] ); diff[1] = ( p[i].swim.v_center[1] - p[i].swim.v_source[1] ); diff[2] = ( p[i].swim.v_center[2] - p[i].swim.v_source[2] ); cross[0] = diff[1]*dip[2] - diff[2]*dip[1]; cross[1] = diff[0]*dip[2] - diff[2]*dip[0]; cross[2] = diff[0]*dip[1] - diff[1]*dip[0]; l_diff = sqrt(diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); l_cross = sqrt(cross[0]*cross[0] + cross[1]*cross[1] + cross[2]*cross[2]); if ( l_cross > 0 && p[i].swim.dipole_length > 0 ) { omega_swim[0] = l_diff * cross[0] / ( l_cross * p[i].swim.dipole_length ); omega_swim[1] = l_diff * cross[1] / ( l_cross * p[i].swim.dipole_length ); omega_swim[2] = l_diff * cross[2] / ( l_cross * p[i].swim.dipole_length ); omega_swim_body[0] = A[0 + 3*0]*omega_swim[0] + A[0 + 3*1]*omega_swim[1] + A[0 + 3*2]*omega_swim[2]; omega_swim_body[1] = A[1 + 3*0]*omega_swim[0] + A[1 + 3*1]*omega_swim[1] + A[1 + 3*2]*omega_swim[2]; omega_swim_body[2] = A[2 + 3*0]*omega_swim[0] + A[2 + 3*1]*omega_swim[1] + A[2 + 3*2]*omega_swim[2]; p[i].f.torque[0] += p[i].swim.rotational_friction * ( omega_swim_body[0] - p[i].m.omega[0] ); p[i].f.torque[1] += p[i].swim.rotational_friction * ( omega_swim_body[1] - p[i].m.omega[1] ); p[i].f.torque[2] += p[i].swim.rotational_friction * ( omega_swim_body[2] - p[i].m.omega[2] ); } } #endif ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: SCAL f = (%.3e,%.3e,%.3e) v_old = (%.3e,%.3e,%.3e)\n",this_node,p[i].f.f[0],p[i].f.f[1],p[i].f.f[2],p[i].m.v[0],p[i].m.v[1],p[i].m.v[2])); #ifdef ROTATIONAL_INERTIA p[i].m.omega[0]+= time_step_half*p[i].f.torque[0]/p[i].p.rinertia[0]/I[0]; p[i].m.omega[1]+= time_step_half*p[i].f.torque[1]/p[i].p.rinertia[1]/I[1]; p[i].m.omega[2]+= time_step_half*p[i].f.torque[2]/p[i].p.rinertia[2]/I[2]; #else p[i].m.omega[0]+= time_step_half*p[i].f.torque[0]/I[0]; p[i].m.omega[1]+= time_step_half*p[i].f.torque[1]/I[1]; p[i].m.omega[2]+= time_step_half*p[i].f.torque[2]/I[2]; #endif /* if the tensor of inertia is isotropic, the following refinement is not needed. Otherwise repeat this loop 2-3 times depending on the required accuracy */ for(int times=0; times <= 5; times++) { double Wd[3]; #ifdef ROTATIONAL_INERTIA Wd[0] = (p[i].m.omega[1]*p[i].m.omega[2]*(I[1]-I[2]))/I[0]/p[i].p.rinertia[0]; Wd[1] = (p[i].m.omega[2]*p[i].m.omega[0]*(I[2]-I[0]))/I[1]/p[i].p.rinertia[1]; Wd[2] = (p[i].m.omega[0]*p[i].m.omega[1]*(I[0]-I[1]))/I[2]/p[i].p.rinertia[2]; #else Wd[0] = (p[i].m.omega[1]*p[i].m.omega[2]*(I[1]-I[2]))/I[0]; Wd[1] = (p[i].m.omega[2]*p[i].m.omega[0]*(I[2]-I[0]))/I[1]; Wd[2] = (p[i].m.omega[0]*p[i].m.omega[1]*(I[0]-I[1]))/I[2]; #endif p[i].m.omega[0]+= time_step_half*Wd[0]; p[i].m.omega[1]+= time_step_half*Wd[1]; p[i].m.omega[2]+= time_step_half*Wd[2]; } ONEPART_TRACE(if(p[i].p.identity==check_id) fprintf(stderr,"%d: OPT: PV_2 v_new = (%.3e,%.3e,%.3e)\n",this_node,p[i].m.v[0],p[i].m.v[1],p[i].m.v[2])); } } }