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); }
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); }