public double Evolve(double time, GravityState gravityState, ref byte[] info) { double[] mass = gravityState.m; double[,] pos = gravityState.r; this.gravityState = gravityState; t_offset = 0; t_evolveStart = gravityState.GetPhysicsTime(); int nloops = 0; if (dt > time) { dt = time; } while (t_offset < time) { // If only one body collision time will be MAXFLOAT t_offset += dt; Evolve_step(ref mass, ref pos, ref info); // timestep adjustement, relative to initial collision time coll_time_avg = COLL_AVERAGE_FACTOR * coll_time_avg + (1 - COLL_AVERAGE_FACTOR) * coll_time; dt = dtInitial * coll_time_avg / coll_time_initial; if (dt > maxDt) { dt = maxDt; } else if (dt < minDt) { dt = minDt; } nloops++; } #pragma warning disable 162 // disable unreachable code warning if (GravityEngine.DEBUG) { if (logCount++ > LOG_INTERVAL) { logCount = 0; Debug.LogFormat("time={0} dt={1} coll_time={2} coll_factor={3} coll_time_initial={4} nloops={5} numbodies={6}", time, dt, coll_time, coll_time_avg / coll_time_initial, coll_time_initial, nloops, numBodies); } } #pragma warning restore 162 return(t_offset); }
/// <summary> /// Evolves using the force delegate. Internals differ slightly and for effeciency do not want /// a conditional on forceDelegate in the inner loop. /// /// </summary> /// <returns>The force delegate.</returns> /// <param name="time">Time.</param> /// <param name="m">M.</param> /// <param name="r">The red component.</param> /// <param name="info">Info.</param> private double EvolveForceDelegate(double time, GravityState gravityState, ref byte[] info) { int numSteps = 0; double[] m = gravityState.m; double[,] r = gravityState.r; // advance acceleration double r2; double r_sep; double f; double timeNow = gravityState.GetPhysicsTime(); double dummy = 0; // If objects are fixed want to use their mass but not update their position // Better to calc their acceleration and ignore than add an if statement to core loop. for (double t = 0; t < time; t += dt) { numSteps++; // Update v and r for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.INACTIVE_OR_FIXED) == 0) { v[i, 0] += a[i, 0] * 0.5 * dt; r[i, 0] += v[i, 0] * dt; v[i, 1] += a[i, 1] * 0.5 * dt; r[i, 1] += v[i, 1] * dt; v[i, 2] += a[i, 2] * 0.5 * dt; r[i, 2] += v[i, 2] * dt; } } // a = 0 // a = 0 or init with eternal value for (int i = 0; i < numBodies; i++) { if (externalAccel[i] != null) { double[] e_accel = externalAccel[i].acceleration(timeNow + t, gravityState, ref dummy); a[i, 0] = e_accel[0]; a[i, 1] = e_accel[1]; a[i, 2] = e_accel[2]; } else { a[i, 0] = 0.0; a[i, 1] = 0.0; a[i, 2] = 0.0; } } // calc a for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.INACTIVE) == 0) { for (int j = i + 1; j < numBodies; j++) { if ((info[j] & GravityEngine.INACTIVE) == 0) { // O(N^2) in here, unpack loops to optimize r2 = 0; rji[0] = r[j, 0] - r[i, 0]; r2 += rji[0] * rji[0]; rji[1] = r[j, 1] - r[i, 1]; r2 += rji[1] * rji[1]; rji[2] = r[j, 2] - r[i, 2]; r2 += rji[2] * rji[2]; r_sep = System.Math.Sqrt(r2) + EPSILON; f = forceDelegate.CalcPseudoForce(r_sep, i, j); a[i, 0] += m[j] * f * (rji[0] / r_sep); a[i, 1] += m[j] * f * (rji[1] / r_sep); a[i, 2] += m[j] * f * (rji[2] / r_sep); a[j, 0] -= m[i] * f * (rji[0] / r_sep); a[j, 1] -= m[i] * f * (rji[1] / r_sep); a[j, 2] -= m[i] * f * (rji[2] / r_sep); } } } } // update velocity for (int i = 0; i < numBodies; i++) { if ((info[i] & GravityEngine.FIXED_MOTION) == 0) { v[i, 0] += a[i, 0] * 0.5 * dt; v[i, 1] += a[i, 1] * 0.5 * dt; v[i, 2] += a[i, 2] * 0.5 * dt; //DebugBody(i, ref m, ref r, "evolve"); } } // coll_time code } return(numSteps * dt); }