/* A list of trapped molecules present on this node is created (local_trapped_mols)*/ void get_local_trapped_mols (IntList *local_trapped_mols) { int c, i, mol, j, fixed; for (c = 0; c < local_cells.n; c++) { for(i = 0; i < local_cells.cell[c]->n; i++) { mol = local_cells.cell[c]->part[i].p.mol_id; if ( mol >= n_molecules ) { ostringstream msg; msg <<"can't calculate molforces no such molecule as " << mol ; runtimeError(msg); return; } /* Check to see if this molecule is fixed */ fixed =0; for(j = 0; j < 3; j++) { #ifdef EXTERNAL_FORCES if (topology[mol].trap_flag & COORD_FIXED(j)) fixed = 1; if (topology[mol].noforce_flag & COORD_FIXED(j)) fixed = 1; #endif } if (fixed) { /* if this molecule isn't already in local_trapped_mols then add it in */ if (!intlist_contains(local_trapped_mols,mol)) { realloc_intlist(local_trapped_mols, local_trapped_mols->max + 1); local_trapped_mols->e[local_trapped_mols->max-1] = mol; local_trapped_mols->n = local_trapped_mols->max; } } } } }
/* A list of trapped molecules present on this node is created (local_trapped_mols)*/ void get_local_trapped_mols (IntList *local_trapped_mols) { int c, i, mol, j, fixed; for (c = 0; c < local_cells.n; c++) { for(i = 0; i < local_cells.cell[c]->n; i++) { mol = local_cells.cell[c]->part[i].p.mol_id; if ( mol >= n_molecules ) { char *errtxt = runtime_error(128 + 3*TCL_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{ 094 can't calculate molforces no such molecule as %d }",mol); return; } /* Check to see if this molecule is fixed */ fixed =0; for(j = 0; j < 3; j++) { #ifdef EXTERNAL_FORCES if (topology[mol].trap_flag & COORD_FIXED(j)) fixed = 1; if (topology[mol].noforce_flag & COORD_FIXED(j)) fixed = 1; #endif } if (fixed) { /* if this molecule isn't already in local_trapped_mols then add it in */ if (!intlist_contains(local_trapped_mols,mol)) { realloc_intlist(local_trapped_mols, local_trapped_mols->max + 1); local_trapped_mols->e[local_trapped_mols->max-1] = mol; local_trapped_mols->n = local_trapped_mols->max; } } } } }
/* calculates the force applies by traps on all molecules */ void calc_trap_force() { Molecule *m; int mi,j; #ifdef EXTERNAL_FORCES double trappos; #endif if ( !topo_part_info_synced ) { ostringstream msg; msg <<"can't calculate moltrap: must execute analyse set topo_part_sync first"; runtimeError(msg); return; } else { m = &topology[0]; for (mi = 0; mi < n_molecules; mi++) { m = &topology[mi]; for(j = 0; j < 3; j++) { #ifdef EXTERNAL_FORCES if (m->trap_flag & COORD_FIXED(j)) { /* Is the molecule trapped at a certain position in space? */ if (m->isrelative == 1) { /* Is the trap set to absolute coordinates... */ trappos = m->trap_center[j]*box_l[j]; } else { /* or to relative ones? */ trappos = m->trap_center[j]; } m->trap_force[j] = 0; /* the trap_force holding the molecule to the set position in calculated */ m->trap_force[j] += -((m->com[j]-trappos)*m->trap_spring_constant)/(double)(m->part.n); /* the drag force applied to the molecule is calculated */ m->trap_force[j] += -(m->v[j]*m->drag_constant)/(double)(m->part.n); /* the force applies by the traps is added to fav */ /* favcounter counts how many times we have added the force to fav since last time "analyze mol force" was called */ /* upon Espresso initialization it is set to -1 because in the first call of "integrate" there is an extra initial time step */ /* calling "analyze mol force" resets favcounter to 0 */ if (m->favcounter > -1) m->fav[j] -= m->v[j]*m->drag_constant + (m->com[j]-trappos)*m->trap_spring_constant; } if (m->noforce_flag & COORD_FIXED(j)) { /* the trap force required to cancel out the total force acting on the molecule is calculated */ m->trap_force[j] -= m->f[j]/(double)m->part.n; if (m->favcounter > -1) m->fav[j] -= m->f[j]; } #endif } m->favcounter++; } } }
bool steepest_descent_step(void) { Cell *cell; Particle *p; int c, i, j, np; double f_max = -std::numeric_limits<double>::max(); double f; /* Verlet list criterion */ const double skin2 = SQR(0.5*skin); double f_max_global; double dx[3], dx2; const double max_dx2 = SQR(params->max_displacement); 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++) { f = 0.0; dx2 = 0.0; #ifdef VIRTUAL_SITES if (ifParticleIsVirtual(&p[i])) continue; #endif for(j=0; j < 3; j++){ #ifdef EXTERNAL_FORCES if (!(p[i].p.ext_flag & COORD_FIXED(j))) #endif { f += SQR(p[i].f.f[j]); dx[j] = params->gamma * p[i].f.f[j]; dx2 += SQR(dx[j]); MINIMIZE_ENERGY_TRACE(printf("part %d dim %d dx %e gamma*f %e\n", i, j, dx[j], params->gamma * p[i].f.f[j])); } #ifdef EXTERNAL_FORCES else { dx[j] = 0.0; } #endif } if(dx2 <= max_dx2) { p[i].r.p[0] += dx[0]; p[i].r.p[1] += dx[1]; p[i].r.p[2] += dx[2]; } else { const double c = params->max_displacement/std::sqrt(dx2); p[i].r.p[0] += c*dx[0]; p[i].r.p[1] += c*dx[1]; p[i].r.p[2] += c*dx[2]; } if(distance2(p[i].r.p,p[i].l.p_old) > skin2 ) resort_particles = 1; f_max = std::max(f_max, f); } } MINIMIZE_ENERGY_TRACE(printf("f_max %e resort_particles %d\n", f_max, resort_particles)); announce_resort_particles(); MPI_Allreduce(&f_max, &f_max_global, 1, MPI_DOUBLE, MPI_MAX, comm_cart); return (sqrt(f_max_global) < params->f_max); }
void rescale_forces_propagate_vel() { Cell *cell; Particle *p; int i, j, np, c; double scale; #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO){ nptiso.p_vel[0] = nptiso.p_vel[1] = nptiso.p_vel[2] = 0.0;} #endif scale = 0.5 * time_step * time_step; INTEG_TRACE(fprintf(stderr,"%d: rescale_forces_propagate_vel:\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++) { check_particle_force(&p[i]); /* Rescale forces: f_rescaled = 0.5*dt*dt * f_calculated * (1/mass) */ p[i].f.f[0] *= scale/PMASS(p[i]); p[i].f.f[1] *= scale/PMASS(p[i]); p[i].f.f[2] *= scale/PMASS(p[i]); 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 VIRTUAL_SITES // Virtual sites are not propagated during integration if (ifParticleIsVirtual(&p[i])) continue; #endif for(j = 0; j < 3 ; j++) { #ifdef EXTERNAL_FORCES if (!(p[i].l.ext_flag & COORD_FIXED(j))) { #endif #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO && ( nptiso.geometry & nptiso.nptgeom_dir[j] )) { nptiso.p_vel[j] += SQR(p[i].m.v[j])*PMASS(p[i]); p[i].m.v[j] += p[i].f.f[j] + friction_therm0_nptiso(p[i].m.v[j])/PMASS(p[i]); } else #endif /* Propagate velocity: v(t+dt) = v(t+0.5*dt) + 0.5*dt * f(t+dt) */ { p[i].m.v[j] += p[i].f.f[j]; } #ifdef EXTERNAL_FORCES } #endif } 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])); } } #ifdef NPT finalize_p_inst_npt(); #endif }
void propagate_press_box_pos_and_rescale_npt() { #ifdef NPT if(integ_switch == INTEG_METHOD_NPT_ISO) { Cell *cell; Particle *p; int i, j, np, c; double scal[3]={0.,0.,0.}, L_new=0.0; /* finalize derivation of p_inst */ finalize_p_inst_npt(); /* adjust \ref nptiso_struct::nptiso.volume; prepare pos- and vel-rescaling */ if (this_node == 0) { nptiso.volume += nptiso.inv_piston*nptiso.p_diff*0.5*time_step; scal[2] = SQR(box_l[nptiso.non_const_dim])/pow(nptiso.volume,2.0/nptiso.dimension); nptiso.volume += nptiso.inv_piston*nptiso.p_diff*0.5*time_step; if (nptiso.volume < 0.0) { char *errtxt = runtime_error(128 + 3*TCL_DOUBLE_SPACE); ERROR_SPRINTF(errtxt, "{015 your choice of piston=%g, dt=%g, p_diff=%g just caused the volume to become negative, decrease dt} ", nptiso.piston,time_step,nptiso.p_diff); nptiso.volume = box_l[0]*box_l[1]*box_l[2]; scal[2] = 1; } L_new = pow(nptiso.volume,1.0/nptiso.dimension); // printf(stdout,"Lnew, %f: volume, %f: dim, %f: press, %f \n", L_new, nptiso.volume, nptiso.dimension,nptiso.p_inst ); // fflush(stdout); scal[1] = L_new/box_l[nptiso.non_const_dim]; scal[0] = 1/scal[1]; } MPI_Bcast(scal, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); /* propagate positions while rescaling positions and velocities */ 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 VIRTUAL_SITES if (ifParticleIsVirtual(&p[i])) continue; #endif for(j=0; j < 3; j++){ #ifdef EXTERNAL_FORCES if (!(p[i].l.ext_flag & COORD_FIXED(j))) { #endif if(nptiso.geometry & nptiso.nptgeom_dir[j]) { p[i].r.p[j] = scal[1]*(p[i].r.p[j] + scal[2]*p[i].m.v[j]); p[i].l.p_old[j] *= scal[1]; p[i].m.v[j] *= scal[0]; } else { p[i].r.p[j] += p[i].m.v[j]; } #ifdef EXTERNAL_FORCES } #endif } 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])); 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])); #ifdef ADDITIONAL_CHECKS force_and_velocity_check(&p[i]); #endif } } resort_particles = 1; /* Apply new volume to the box-length, communicate it, and account for necessary adjustments to the cell geometry */ if (this_node == 0) { for ( i = 0 ; i < 3 ; i++ ){ if ( nptiso.geometry & nptiso.nptgeom_dir[i] ) { box_l[i] = L_new; } else if ( nptiso.cubic_box ) { box_l[i] = L_new; } } } MPI_Bcast(box_l, 3, MPI_DOUBLE, 0, MPI_COMM_WORLD); on_NpT_boxl_change(); }
int tclcommand_analyze_set_parse_trapmol(Tcl_Interp *interp, int argc, char **argv) { #ifdef MOLFORCES #ifdef EXTERNAL_FORCES int trap_flag = 0; int noforce_flag =0; int i; #endif #endif int mol_num; double spring_constant; double drag_constant; int isrelative; DoubleList trap_center; IntList trap_coords; IntList noforce_coords; char usage[] = "trapmol usage: <mol_id> { <xpos> <ypos> <zpos> } <isrelative> <spring_constant> <drag_constant> coords { <trapped_coord> <trapped_coord> <trapped_coord> } noforce_coords {<noforce_coord> <noforce_coord> <noforce_coord>}"; init_doublelist(&trap_center); init_intlist(&trap_coords); alloc_intlist(&trap_coords,3); init_intlist(&noforce_coords); alloc_intlist(&noforce_coords,3); /* Unless coords are specified the default is just to trap it completely */ trap_coords.e[0] = 1; trap_coords.e[1] = 1; trap_coords.e[2] = 1; Tcl_ResetResult(interp); /* The first argument should be a molecule number */ if (!ARG0_IS_I(mol_num)) { Tcl_AppendResult(interp, "first argument should be a molecule id", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } else { /* Sanity checks */ if (mol_num > n_molecules) { Tcl_AppendResult(interp, "trapmol: cannot trap mol %d because it does not exist",mol_num , (char *)NULL); return TCL_ERROR; } argc--; argv++; } /* The next argument should be a double list specifying the trap center */ if (!ARG0_IS_DOUBLELIST(trap_center)) { Tcl_AppendResult(interp, "second argument should be a double list", (char *)NULL); Tcl_AppendResult(interp, usage , (char *)NULL); return TCL_ERROR; } else { argc -= 1; argv += 1; } /* The next argument should be an integer specifying whether the trap is relative (fraction of box_l) or absolute */ if (!ARG0_IS_I(isrelative)) { Tcl_AppendResult(interp, "third argument should be an integer", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } else { argc -= 1; argv += 1; } /* The next argument should be the spring constant for the trap */ if (!ARG0_IS_D(spring_constant)) { Tcl_AppendResult(interp, "fourth argument should be a double", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } else { argc -= 1; argv += 1; } /* The next argument should be the drag constant for the trap */ if (!ARG0_IS_D(drag_constant)) { Tcl_AppendResult(interp, "fifth argument should be a double", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } else { argc -= 1; argv += 1; } /* Process optional arguments */ while ( argc > 0 ) { if ( ARG0_IS_S("coords") ) { if ( !ARG_IS_INTLIST(1,trap_coords) ) { Tcl_AppendResult(interp, "an intlist is required to specify coords", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } argc -= 2; argv += 2; } else if ( ARG0_IS_S("noforce_coords")) { if ( !ARG_IS_INTLIST(1,noforce_coords) ) { Tcl_AppendResult(interp, "an intlist is required to specify coords", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } argc -= 2; argv += 2; } else { Tcl_AppendResult(interp, "an option is not recognised", (char *)NULL); Tcl_AppendResult(interp, usage, (char *)NULL); return TCL_ERROR; } } #ifdef MOLFORCES #ifdef EXTERNAL_FORCES for (i = 0; i < 3; i++) { if (trap_coords.e[i]) trap_flag |= COORD_FIXED(i); if (noforce_coords.e[i]) noforce_flag |= COORD_FIXED(i); } if (set_molecule_trap(mol_num, trap_flag,&trap_center,spring_constant, drag_constant, noforce_flag, isrelative) == TCL_ERROR) { Tcl_AppendResult(interp, "set topology first", (char *)NULL); return TCL_ERROR; } #else Tcl_AppendResult(interp, "Error: EXTERNAL_FORCES not defined ", (char *)NULL); return TCL_ERROR; #endif #endif realloc_doublelist(&trap_center,0); realloc_intlist(&trap_coords,0); realloc_intlist(&noforce_coords,0); return tclcommand_analyze_set_parse_topo_part_sync(interp); }
/* This is only done for the trapped molecules to save time */ void calc_local_mol_info (IntList *local_trapped_mols) { int mi, i,j, mol; Particle *p; int np, c; Cell *cell; int lm; int fixed; /* First reset all molecule masses,forces,centers of mass*/ for ( mi = 0 ; mi < n_molecules ; mi++ ) { topology[mi].mass = 0; for ( i = 0 ; i < 3 ; i++) { topology[mi].f[i] = 0.0; topology[mi].com[i] = 0.0; topology[mi].v[i] = 0.0; } } 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++) { mol = p[i].p.mol_id; if ( mol >= n_molecules ) { char *errtxt = runtime_error(128 + 3*TCL_INTEGER_SPACE); ERROR_SPRINTF(errtxt, "{ 094 can't calculate molforces no such molecule as %d }",mol); return; } /* Check to see if this molecule is fixed */ fixed =0; for(j = 0; j < 3; j++) { #ifdef EXTERNAL_FORCES if (topology[mol].trap_flag & COORD_FIXED(j)) fixed = 1; if (topology[mol].noforce_flag & COORD_FIXED(j)) fixed = 1; #endif } if (fixed) { topology[mol].mass += PMASS(p[i]); /* Unfold the particle */ unfold_position(p[i].r.p,p[i].l.i); for ( j = 0 ; j < 3 ; j++ ) { topology[mol].f[j] += p[i].f.f[j]; topology[mol].com[j] += p[i].r.p[j]*PMASS(p[i]); topology[mol].v[j] += p[i].m.v[j]*PMASS(p[i]); } /* Fold the particle back */ fold_position(p[i].r.p,p[i].l.i); } } } /* Final normalisation of centers of mass and velocity*/ for ( lm = 0 ; lm < local_trapped_mols->n; lm++ ) { mi = local_trapped_mols->e[lm]; for ( i = 0 ; i < 3 ; i++) { topology[mi].com[i] = topology[mi].com[i]/(double)(topology[mi].mass); topology[mi].v[i] = topology[mi].v[i]/(double)(topology[mi].mass); } } }
void propagate_pos_sd() { /* Verlet list criterion */ double skin2 = SQR(0.5 * skin); INTEG_TRACE(fprintf(stderr,"%d: propagate_pos:\n",this_node)); Cell *cell; Particle *p; int c, i, np; //get total number of particles int N=sd_get_particle_num(); // gather all the data for mobility calculation real * pos=NULL; pos=(real *)Utils::malloc(DIM*N*sizeof(double)); assert(pos!=NULL); real * force=NULL; force=(real *)Utils::malloc(DIM*N*sizeof(double)); assert(force!=NULL); real * velocity=NULL; velocity=(real *)Utils::malloc(DIM*N*sizeof(real)); assert(velocity!=NULL); #ifdef EXTERNAL_FORCES const int COORD_ALL=COORD_FIXED(0)&COORD_FIXED(1)&COORD_FIXED(2); #endif int j=0; // total particle counter 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++) { // only count nonVirtual Particles #ifdef EXTERNAL_FORCES if (p[i].p.ext_flag & COORD_ALL) { fprintf (stderr, "Warning: Fixing particle in StokesDynamics this way with EXTERNAL_FORCES is not possible (and will be ignored). Please try to bind them e.g. harmonicaly.\n"); } #endif #ifdef VIRTUAL_SITES if (!ifParticleIsVirtual(&p[i])) #endif { #ifdef SD_USE_FLOAT for (int d=0;d<3;d++){ pos[3*j+d] = p[i].r.p[d]; pos[3*j+d] -=rint(pos[3*j+d]/box_l[d])*box_l[d]; force[3*j+d] = p[i].f.f[d]; } #else memmove(&pos[3*j], p[i].r.p, 3*sizeof(double)); memmove(&force[3*j], p[i].f.f, 3*sizeof(double)); for (int d=0;d<3;d++){ pos[3*j+d] -=rint(pos[3*j+d]/box_l[d])*box_l[d]; } #endif j++; } } } if (!(thermo_switch & THERMO_SD) && thermo_switch & THERMO_BD){ propagate_pos_bd(N,pos,force, velocity); } else { // cuda part #ifdef CUDA //void propagate_pos_sd_cuda(double * box_l_h, int N,double * pos_h, double * force_h, double * velo_h){ #ifdef SD_USE_FLOAT real box_size[3]; for (int d=0;d<3;d++){ box_size[d]=box_l[d]; } #else real * box_size = box_l; #endif if (!(thermo_switch & THERMO_SD)){ temperature*=-1; } propagate_pos_sd_cuda(box_size,N,pos,force, velocity); if (!(thermo_switch & THERMO_SD)){ temperature*=-1; } #else fprintf(stderr, "Warning - CUDA is currently required for SD\n"); fprintf(stderr, "So i am just sitting here and copying stupidly stuff :'(\n"); #endif } #ifdef NEMD /* change momentum of each particle in top and bottom slab */ fprintf (stderr, "Warning: NEMD is in SD not supported.\n"); #endif j=0; 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 VIRTUAL_SITES if (ifParticleIsVirtual(&p[i])) continue; #endif // write back of position and velocity data #ifdef SD_USE_FLOAT for (int d=0;d<3;d++){ p[i].r.p[d] = pos[3*j+d]+box_l[d]*rint(p[i].r.p[d]/box_l[d]); p[i].m.v[d] = velocity[3*j+d]; //p[i].f.f[d] *= (0.5*time_step*time_step)/(*part).p.mass; } #else for (int d=0;d<3;d++){ p[i].r.p[d] = pos[3*j+d]+box_l[d]*rint(p[i].r.p[d]/box_l[d]); } memmove(p[i].m.v, &velocity[DIM*j], 3*sizeof(double)); #endif // somehow this does not effect anything, although it is called ... for (int d=0;d<3;d++){ p[i].f.f[d] *= (0.5*time_step*time_step)/(*p).p.mass; } for (int d=0;d<DIM;d++){ assert(!isnan(pos[DIM*i+d])); } 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])); 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])); #ifdef ROTATION propagate_omega_quat_particle(&p[i]); #endif /* Verlet criterion check */ if(distance2(p[i].r.p,p[i].l.p_old) > skin2 ) resort_particles = 1; } } free(pos); free(force); free(velocity); announce_resort_particles(); }
/** overwrite the forces of a particle with the friction term, i.e. \f$ F_i= -\gamma v_i + \xi_i\f$. */ inline void friction_thermo_langevin(Particle *p) { extern double langevin_pref1, langevin_pref2; double langevin_pref1_temp, langevin_pref2_temp; #ifdef MULTI_TIMESTEP extern double langevin_pref1_small; #ifndef LANGEVIN_PER_PARTICLE extern double langevin_pref2_small; #endif /* LANGEVIN_PER_PARTICLE */ #endif /* MULTI_TIMESTEP */ int j; double switch_trans = 1.0; if ( langevin_trans == false ) { switch_trans = 0.0; } // Virtual sites related decision making #ifdef VIRTUAL_SITES #ifndef VIRTUAL_SITES_THERMOSTAT // In this case, virtual sites are NOT thermostated if (ifParticleIsVirtual(p)) { for (j=0; j<3; j++) p->f.f[j]=0; return; } #endif /* VIRTUAL_SITES_THERMOSTAT */ #ifdef THERMOSTAT_IGNORE_NON_VIRTUAL // In this case NON-virtual particles are NOT thermostated if (!ifParticleIsVirtual(p)) { for (j=0; j<3; j++) p->f.f[j]=0; return; } #endif /* THERMOSTAT_IGNORE_NON_VIRTUAL */ #endif /* VIRTUAL_SITES */ // Get velocity effective in the thermostatting double velocity[3]; for (int i = 0; i < 3; i++) { // Particle velocity velocity[i] = p->m.v[i]; #ifdef ENGINE // In case of the engine feature, the velocity is relaxed // towards a swimming velocity oriented parallel to the // particles director velocity[i] -= (p->swim.v_swim*time_step)*p->r.quatu[i]; #endif // Local effective velocity for leeds-edwards boundary conditions velocity[i]=le_frameV(i,velocity,p->r.p); } // for // Determine prefactors for the friction and the noise term // first, set defaults langevin_pref1_temp = langevin_pref1; langevin_pref2_temp = langevin_pref2; // Override defaults if per-particle values for T and gamma are given #ifdef LANGEVIN_PER_PARTICLE // If a particle-specific gamma is given if(p->p.gamma >= 0.) { langevin_pref1_temp = -p->p.gamma/time_step; // Is a particle-specific temperature also specified? if(p->p.T >= 0.) langevin_pref2_temp = sqrt(24.0*p->p.T*p->p.gamma/time_step); else // Default temperature but particle-specific gamma langevin_pref2_temp = sqrt(24.0*temperature*p->p.gamma/time_step); } // particle specific gamma else { langevin_pref1_temp = -langevin_gamma/time_step; // No particle-specific gamma, but is there particle-specific temperature if(p->p.T >= 0.) langevin_pref2_temp = sqrt(24.0*p->p.T*langevin_gamma/time_step); else // Defaut values for both langevin_pref2_temp = langevin_pref2; } #endif /* LANGEVIN_PER_PARTICLE */ // Multi-timestep handling // This has to be last, as it may set the prefactors to 0. #ifdef MULTI_TIMESTEP if (smaller_time_step > 0.) { langevin_pref1_temp *= time_step/smaller_time_step; if (p->p.smaller_timestep==1 && current_time_step_is_small==1) langevin_pref2_temp *= sqrt(time_step/smaller_time_step); else if (p->p.smaller_timestep != current_time_step_is_small) { langevin_pref1_temp = 0.; langevin_pref2_temp = 0.; } } #endif /* MULTI_TIMESTEP */ // Do the actual thermostatting for ( j = 0 ; j < 3 ; j++) { #ifdef EXTERNAL_FORCES // If individual coordinates are fixed, set force to 0. if ((p->p.ext_flag & COORD_FIXED(j))) p->f.f[j] = 0; else #endif { // Apply the force p->f.f[j] = langevin_pref1_temp*velocity[j] + switch_trans*langevin_pref2_temp*noise; } } // END LOOP OVER ALL COMPONENTS // printf("%d: %e %e %e %e %e %e\n",p->p.identity, p->f.f[0],p->f.f[1],p->f.f[2], p->m.v[0],p->m.v[1],p->m.v[2]); ONEPART_TRACE(if(p->p.identity==check_id) fprintf(stderr,"%d: OPT: LANG f = (%.3e,%.3e,%.3e)\n",this_node,p->f.f[0],p->f.f[1],p->f.f[2])); THERMO_TRACE(fprintf(stderr,"%d: Thermo: P %d: force=(%.3e,%.3e,%.3e)\n",this_node,p->p.identity,p->f.f[0],p->f.f[1],p->f.f[2])); }
bool steepest_descent_step(void) { Cell *cell; Particle *p; int c, i, j, np; // Maximal force encountered on node double f_max = -std::numeric_limits<double>::max(); // and globally double f_max_global; // Square of force,torque on particle double f,t; // Positional increments double dp, dp2, dp2_max = -std::numeric_limits<double>::max(); // Iteration over all local particles 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++) { f = 0.0; t = 0.0; dp2 = 0.0; #ifdef EXTERNAL_FORCES // Skip, if coordinate is fixed if (!(p[i].p.ext_flag & COORD_FIXED(j))) #endif // For all Cartesian coordinates for(j=0; j < 3; j++){ #ifdef VIRTUAL_SITES // Skip positional increments of virtual particles if (!ifParticleIsVirtual(&p[i])) #endif { // Square of force on particle f += SQR(p[i].f.f[j]); // Positional increment dp = params->gamma * p[i].f.f[j]; if(fabs(dp) > params->max_displacement) // Crop to maximum allowed by user dp = sgn<double>(dp)*params->max_displacement; dp2 += SQR(dp); // Move particle p[i].r.p[j] += dp; MINIMIZE_ENERGY_TRACE(printf("part %d dim %d dp %e gamma*f %e\n", i, j, dp, params->gamma * p[i].f.f[j])); } } #ifdef ROTATION // Rotational increment double dq[3]; // Vector parallel to torque for (int j=0;j<3;j++){ dq[j]=0; // Square of torque t += SQR(p[i].f.torque[j]); // Rotational increment dq[j] = params->gamma * p[i].f.torque[j]; } // Normalize rotation axis and compute amount of rotation double l=normr(dq); if (l>0.0) { for (j=0;j<3;j++) dq[j]/=l; if(fabs(l) > params->max_displacement) // Crop to maximum allowed by user l=sgn(l)*params->max_displacement; // printf("dq: %g %g %g, l=%g\n",dq[0],dq[1],dq[2],l); // Rotate the particle around axis dq by amount l rotate_particle(&(p[i]),dq,l); } #endif // Note maximum force/torque encountered f_max = std::max(f_max, f); f_max = std::max(f_max, t); dp2_max = std::max(dp2_max, dp2); resort_particles = 1; } } MINIMIZE_ENERGY_TRACE(printf("f_max %e resort_particles %d\n", f_max, resort_particles)); announce_resort_particles(); // Synchronize maximum force/torque encountered MPI_Allreduce(&f_max, &f_max_global, 1, MPI_DOUBLE, MPI_MAX, comm_cart); // Return true, if the maximum force/torque encountered is below the user limit. return (sqrt(f_max_global) < params->f_max); }