@@ -204,8 +204,6 @@ void setup() {
204204 currentTime = 0 ;
205205 // Wrap the canvas.
206206 canvasWrapper = new CanvasWrapper (canvas , gridCanvas , trailCanvas );
207- // Set up the integrator that we will be using. The minimum step size is 10 ^ -20, so that the integrator will return errors at asymptotes.
208- integrator = new DormandPrince853Integrator (Math .pow (10 , -10 ), 10000 , 0.01 , 0.0001 );
209207 }
210208
211209 /**
@@ -246,6 +244,9 @@ void runSimulation(SimulationSettings settings) {
246244 // Set up the particle differential equation according to the masses of each particle.
247245 particleDifferentialEquations = new ParticleDifferentialEquations (settings .getMass ());
248246
247+ // Set up the integrator that we will be using. The minimum step size is 10 ^ -20, so that the integrator will return errors at asymptotes.
248+ integrator = new DormandPrince853Integrator (Math .pow (10 , -10 ), 10000 , 0.01 , 0.0001 );
249+
249250 // Flatten particles into the flattenedParticles array.
250251 flattenParticles ();
251252
@@ -254,12 +255,28 @@ void runSimulation(SimulationSettings settings) {
254255
255256 // Get position, velocity, acceleration at current time.
256257 if (currentTime != 0 ) {
257- if (!tryToIntegrate (0 , currentTime , flattenedParticles , true )) {
258+ try {
259+ // Get the position and velocity of particles at currentTime
260+ integrator .integrate (particleDifferentialEquations , 0 , flattenedParticles , currentTime , flattenedParticles );
261+ } catch (NumberIsTooSmallException e ) {
262+ // Asymptote error (the integrator can't converge and gives up)
263+ System .out .println (e .getMessage ());
264+ breakSimulationAfterUpdate (FilenameUnspecificMessage .ASYMPTOTE_ERROR );
265+ return ;
266+ } catch (NumberIsTooLargeException e ) {
267+ // Double overflow error (inputs too large for double datatype to handle)
268+ System .out .println (e .getMessage ());
269+ breakSimulationAfterUpdate (FilenameUnspecificMessage .OVERFLOW_ERROR );
270+ return ;
271+ } catch (Exception e ) {
272+ // Other errors
273+ System .out .println (e .getMessage ());
274+ breakSimulationAfterUpdate (FilenameUnspecificMessage .UNKNOWN_ERROR );
258275 return ;
259276 }
260277 }
261278
262- double [][] scales = generateScale (flattenedParticles .clone (), settings );
279+ double [][] scales = generateScale (integrator , flattenedParticles .clone (), settings );
263280
264281 updateParticles ();
265282
@@ -289,99 +306,36 @@ void runSimulation(SimulationSettings settings) {
289306 }
290307 }
291308
292- /**
293- * Attempts to integrate and find particle states at another time.
294- *
295- * @param time0 The current time.
296- * @param time The time to travel to.
297- * @param particles The particles involved.
298- * @param wantErrors Whether errors should be reported to the user (True if you want reports, false otherwise)
299- * @return True if the integration was successful, false otherwise.
300- */
301- @ SuppressWarnings ("BooleanMethodIsAlwaysInverted" ) // Inverted for clarity.
302- private boolean tryToIntegrate (double time0 , double time , double [] particles , boolean wantErrors ) {
303-
304- final boolean [] successfulIntegration = {false };
305-
306- Task <Void > integrationTask = new Task <>() {
307- @ Override
308- protected Void call () {
309- try {
310- integrator .integrate (particleDifferentialEquations , time0 , particles , time , particles );
311- } catch (NumberIsTooSmallException e ) {
312- // Asymptote error catching
313- e .printStackTrace ();
314- if (wantErrors ) {
315- Platform .runLater (() -> breakSimulationAfterUpdate (FilenameUnspecificMessage .ASYMPTOTE_ERROR ));
316- }
317- return null ;
318- } catch (NumberIsTooLargeException e ) {
319- // Double overflow error catching.
320- e .printStackTrace ();
321- if (wantErrors ) {
322- Platform .runLater (() -> breakSimulationAfterUpdate (FilenameUnspecificMessage .OVERFLOW_ERROR ));
323- }
324- return null ;
325- } catch (Exception e ) {
326- // Other errors
327- e .printStackTrace ();
328- if (wantErrors ) {
329- Platform .runLater (() -> breakSimulationAfterUpdate (FilenameUnspecificMessage .UNKNOWN_ERROR ));
330- }
331- return null ;
332- }
333- successfulIntegration [0 ] = true ;
334- return null ;
335- }
336- };
337-
338-
339- // Run the thread.
340- Thread simulationThread = new Thread (integrationTask );
341- simulationThread .setDaemon (true );
342- // For debugging purposes, an exception handler to terminal output is created.
343- simulationThread .setUncaughtExceptionHandler ((t , e ) -> System .out .println (e .getMessage ()));
344-
345- double deadline = System .currentTimeMillis () + 50 ; // half a second
346- simulationThread .start ();
347- while ((!simulationThread .isInterrupted ()) && simulationThread .isAlive ()) {
348- if (System .currentTimeMillis () > deadline ) {
349- simulationThread .interrupt ();
350- if (wantErrors ) {
351- Platform .runLater (() -> breakSimulation (FilenameUnspecificMessage .ASYMPTOTE_ERROR ));
352- }
353- return false ;
354- }
355- }
356- return successfulIntegration [0 ];
357- }
358-
359309 /**
360310 * Calculates the maximum and minimum x/y coordinates during the first ten seconds of simulation.
361311 *
312+ * @param integrator The integrator used.
362313 * @param particles The particles' initial states in flattened form.
363314 * @param settings The settings of the simulation.
364315 * @return The four corners of the smallest possible rectangle that all three particles do not escape in the first 10 seconds of simulation.
365316 */
366- private double [][] generateScale (double [] particles , SimulationSettings settings ) {
317+ private double [][] generateScale (DormandPrince853Integrator integrator , double [] particles , SimulationSettings settings ) {
367318 final int SIMULATION_LENGTH = 10 ;
368319 double simulationTime = currentTime ;
369320
370321 double [][] minsAndMaxs = minAndMaxPositions (particles );
371322
372323 for (double time = simulationTime ; time < SIMULATION_LENGTH * settings .getSpeed () + simulationTime ; time += settings .getSpeed () / 5 ) {
373- if (! tryToIntegrate ( time , time + settings . getSpeed () / 5 , particles , false )) {
374- break ;
375- }
376-
377- double [][] currentMinsAndMaxs = minAndMaxPositions ( particles );
378- for ( int i = 0 ; i < 2 ; i ++ ) {
379- if ( currentMinsAndMaxs [0 ][i ] < minsAndMaxs [0 ][i ]) {
380- minsAndMaxs [ 0 ][ i ] = currentMinsAndMaxs [ 0 ][ i ];
381- }
382- if ( currentMinsAndMaxs [1 ][i ] > minsAndMaxs [1 ][i ]) {
383- minsAndMaxs [ 1 ][ i ] = currentMinsAndMaxs [ 1 ][ i ];
324+ try {
325+ // Get the position and velocity of particles at currentTime
326+ integrator . integrate ( particleDifferentialEquations , time , particles , time + settings . getSpeed () / 5 , particles );
327+ double [][] currentMinsAndMaxs = minAndMaxPositions ( particles );
328+ for ( int i = 0 ; i < 2 ; i ++) {
329+ if ( currentMinsAndMaxs [ 0 ][ i ] < minsAndMaxs [ 0 ][ i ] ) {
330+ minsAndMaxs [0 ][i ] = currentMinsAndMaxs [0 ][i ];
331+ }
332+ if ( currentMinsAndMaxs [ 1 ][ i ] > minsAndMaxs [ 1 ][ i ]) {
333+ minsAndMaxs [1 ][i ] = currentMinsAndMaxs [1 ][i ];
334+ }
384335 }
336+ } catch (Exception e ) {
337+ // All exceptions mean automatic break.
338+ break ;
385339 }
386340 }
387341
@@ -513,7 +467,23 @@ private void startSimulation() {
513467 protected Void call () throws Exception {
514468 while (state == SimulationState .ACTIVE ) { // Break if the simulation becomes inactive or paused.
515469 long taskTime = System .currentTimeMillis (); // Record current time (to sync framerate)
516- if (!tryToIntegrate (currentTime , currentTime + (speed / MAX_FRAMERATE ), flattenedParticles , true )) {
470+ try {
471+ // Store the state of the particles at the next frame.
472+ integrator .integrate (particleDifferentialEquations , currentTime , flattenedParticles , currentTime + (speed / MAX_FRAMERATE ), flattenedParticles );
473+ } catch (NumberIsTooSmallException e ) {
474+ // Asymptote error catching
475+ System .out .println (e .getMessage ());
476+ Platform .runLater (() -> breakSimulationAfterUpdate (FilenameUnspecificMessage .ASYMPTOTE_ERROR ));
477+ break ;
478+ } catch (NumberIsTooLargeException e ) {
479+ // Double overflow error catching.
480+ System .out .println (e .getMessage ());
481+ Platform .runLater (() -> breakSimulationAfterUpdate (FilenameUnspecificMessage .OVERFLOW_ERROR ));
482+ break ;
483+ } catch (Exception e ) {
484+ // Other errors
485+ System .out .println (e .getMessage ());
486+ Platform .runLater (() -> breakSimulationAfterUpdate (FilenameUnspecificMessage .UNKNOWN_ERROR ));
517487 break ;
518488 }
519489
0 commit comments