Skip to content

Commit

Permalink
Add nbody wrapper functionality (#307)
Browse files Browse the repository at this point in the history
* Add nbody wrapper functionality

* Fix linting issues
  • Loading branch information
YeluriKetan authored Apr 10, 2024
1 parent 3178381 commit ba77a2f
Show file tree
Hide file tree
Showing 14 changed files with 842 additions and 6 deletions.
5 changes: 5 additions & 0 deletions modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,10 @@
},
"communication": {
"tabs": []
},
"nbody": {
"tabs": [
"Nbody"
]
}
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"@types/plotly.js-dist": "npm:@types/plotly.js",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/three": "^0.161.2",
"@types/three": "^0.163.0",
"@vitejs/plugin-react": "^4.0.4",
"acorn": "^8.8.1",
"acorn-jsx": "^5.3.2",
Expand Down Expand Up @@ -109,6 +109,7 @@
"js-slang": "^1.0.55",
"lodash": "^4.17.21",
"mqtt": "^4.3.7",
"nbody": "^0.1.1",
"os": "^0.1.2",
"patch-package": "^6.5.1",
"phaser": "^3.54.0",
Expand All @@ -122,7 +123,7 @@
"save-file": "^2.3.1",
"source-academy-utils": "^1.0.0",
"source-academy-wabt": "^1.0.4",
"three": "^0.162.0",
"three": "^0.163.0",
"tslib": "^2.3.1",
"uniqid": "^5.4.0",
"url": "^0.11.3"
Expand Down
75 changes: 75 additions & 0 deletions src/bundles/nbody/CelestialBody.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { CelestialBody, type Vector3 } from 'nbody';

/**
* Create a new celestial body.
* @param label label of the body.
* @param mass mass of the body.
* @param position position of the body.
* @param velocity velocity of the body.
* @param acceleration acceleration of the body.
* @returns A new celestial body.
* @category Celestial Body
*/
export function createCelestialBody(label: string, mass: number, radius?: number, position?: Vector3, velocity?: Vector3, acceleration?: Vector3): CelestialBody {
return new CelestialBody(label, mass, radius, position, velocity, acceleration);
}

/**
* Get the label of a celestial body.
* @param body The celestial body.
* @returns The label of the celestial body.
* @category Celestial Body
*/
export function getLabel(body: CelestialBody): string {
return body.label;
}

/**
* Get the mass of a celestial body.
* @param body The celestial body.
* @returns The mass of the celestial body.
* @category Celestial Body
*/
export function getMass(body: CelestialBody): number {
return body.mass;
}

/**
* Get the radius of a celestial body.
* @param body The celestial body.
* @returns The radius of the celestial body.
* @category Celestial Body
*/
export function getRadius(body: CelestialBody): number {
return body.radius;
}

/**
* Get the position of a celestial body.
* @param body The celestial body.
* @returns The position of the celestial body.
* @category Celestial Body
*/
export function getPosition(body: CelestialBody): Vector3 {
return body.position;
}

/**
* Get the velocity of a celestial body.
* @param body The celestial body.
* @returns The velocity of the celestial body.
* @category Celestial Body
*/
export function getVelocity(body: CelestialBody): Vector3 {
return body.velocity;
}

/**
* Get the acceleration of a celestial body.
* @param body The celestial body.
* @returns The acceleration of the celestial body.
* @category Celestial Body
*/
export function getAcceleration(body: CelestialBody): Vector3 {
return body.acceleration;
}
41 changes: 41 additions & 0 deletions src/bundles/nbody/Force.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { CentripetalForce, CombinedForce, Gravity, type CelestialBody, type Force, type Vector3, LambdaForce } from 'nbody';

/**
* Create a force that applies to all bodies using the provided higher order/lambda/arrow/anonymous function.
* @param fn A function that takes an array of bodies and returns an array of forces of the same length.
* @returns A new lambda force.
* @category Forces
*/
export function createForce(fn: (bodies: CelestialBody[]) => Vector3[]): Force {
return new LambdaForce(fn);
}

/**
* Create a force that applies to all bodies.
* @param G The gravitational constant.
* @returns A new gravity force.
* @category Forces
*/
export function createGravity(G?: number): Gravity {
return new Gravity(G);
}

/**
* Create a centripetal force that pulls bodies towards a center.
* @param center The center of the centripetal force.
* @returns A new centripetal force.
* @category Forces
*/
export function createCentripetalForce(center?: Vector3): CentripetalForce {
return new CentripetalForce(center);
}

/**
* Create a combined force that is an additive combination of all the given forces.
* @param forces The forces to combine.
* @returns A new combined force.
* @category Forces
*/
export function createCombinedForce(forces: Force[]): CombinedForce {
return new CombinedForce(forces);
}
14 changes: 14 additions & 0 deletions src/bundles/nbody/Misc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { CelestialBody, State, Universe, Vector3 } from 'nbody';

/**
* Deep clone an object.
* @param obj The object to clone.
* @returns The cloned object.
* @category Celestial Body
* @category State
* @category Universe
* @category Vector
*/
export function clone(obj: CelestialBody | State | Universe | Vector3): CelestialBody | State | Universe | Vector3 {
return obj.clone();
}
52 changes: 52 additions & 0 deletions src/bundles/nbody/SimulateFunction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ExplicitEulerSim, LambdaSim, RungeKutta4Sim, SemiImplicitEulerSim, VelocityVerletSim, type Force, type State } from 'nbody';

/**
* Create an explicit euler integrator to be used as the simulation function.
* @param force The force that applies to the nbody system.
* @returns A new explicit Euler simulation.
* @category Simulate Functions
*/
export function createExplicitEulerSim(force?: Force): ExplicitEulerSim {
return new ExplicitEulerSim(force);
}

/**
* Create a numerical integrator that uses the Runge-Kutta 4 method to simulate the nbody system.
* @param force The force that applies to the nbody system.
* @param weights The weights to be used for the weighted sum of the k values.
* @returns A new Runge-Kutta 4 simulation.
* @category Simulate Functions
*/
export function createRungeKutta4Sim(force?: Force, weights?: number[]): RungeKutta4Sim {
return new RungeKutta4Sim(force, weights);
}

/**
* Create a numerical integrator that uses the semi-implicit Euler method to simulate the nbody system.
* @param force The force that applies to the nbody system.
* @returns A new semi-implicit Euler simulation.
* @category Simulate Functions
*/
export function createSemiImplicitEulerSim(force?: Force): SemiImplicitEulerSim {
return new SemiImplicitEulerSim(force);
}

/**
* Create a numerical integrator that uses the velocity Verlet method to simulate the nbody system.
* @param force The force that applies to the nbody system.
* @returns A new velocity Verlet simulation.
* @category Simulate Functions
*/
export function createVelocityVerletSim(force: Force): VelocityVerletSim {
return new VelocityVerletSim(force);
}

/**
* Create a simulate function (usually a numerical integrator) that is used to simulate the nbody system using the provided higher order/lambda/arrow/anonymous function.
* @param fn The function to be used as the simulate function.
* @returns A new lambda simulation.
* @category Simulate Functions
*/
export function createLambdaSim(fn: (deltaT: number, prevState: State, currState: State) => State): LambdaSim {
return new LambdaSim(fn);
}
86 changes: 86 additions & 0 deletions src/bundles/nbody/Simulation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import context from 'js-slang/context';
import { RecordingVisualizer, RecordingVisualizer3D, Simulation, type Universe, type VisType } from 'nbody';

/**
* Create a new simulation.
* @param universes The universes to simulate.
* @param visType The visualization type.
* @param record Whether to record the simulation.
* @param looped Whether to loop the simulation.
* @param showTrails Whether to show trails.
* @param showDebugInfo Whether to show debug info
* @param maxTrailLength The maximum length of trails.
* @returns A new simulation.
* @category Simulation
*/
export function createSimulation(universes: Universe[],
visType: VisType,
record?: boolean,
looped?: boolean,
showTrails?: boolean,
maxTrailLength?: number): Simulation {
return new Simulation(universes, {
visType,
record,
looped,
controller: 'code',
showTrails,
maxTrailLength,
});
}

const simulations: Simulation[] = [];
const recordInfo = {
isRecording: false,
recordFor: 0,
recordSpeed: 0,
};

context.moduleContexts.nbody.state = {
simulations,
recordInfo
};

function isRecordingBased(sim: Simulation): boolean {
return sim.visualizer instanceof RecordingVisualizer || sim.visualizer instanceof RecordingVisualizer3D;
}

/**
* Play a simulation.
* @param sim The simulation to play.
* @category Simulation
*/
export function playSim(sim: Simulation): void {
while (simulations.length > 0) {
simulations.pop()!.stop();
}
if (isRecordingBased(sim)) {
throw new Error(
'playSim expects non-recording simulations'
);
}
recordInfo.isRecording = false;
simulations.push(sim);
}

/**
* Record and play a simulation.
* @param sim simulation to record and play.
* @param recordFor time to record for.
* @param recordSpeed speed to record at.
* @category Simulation
*/
export function recordSim(sim: Simulation, recordFor: number, recordSpeed: number): void {
while (simulations.length > 0) {
simulations.pop()!.stop();
}
if (!isRecordingBased(sim)) {
throw new Error(
'recordSim expects recording simulations'
);
}
recordInfo.isRecording = true;
recordInfo.recordFor = recordFor;
recordInfo.recordSpeed = recordSpeed;
simulations.push(sim);
}
21 changes: 21 additions & 0 deletions src/bundles/nbody/State.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { type CelestialBody, State } from 'nbody';

/**
* Create a new state snapshot of the universe.
* @param bodies The bodies in the state.
* @returns A new state.
* @category State
*/
export function createState(bodies: CelestialBody[]): State {
return new State(bodies);
}

/**
* Get the bodies in a state.
* @param state The state.
* @returns The bodies in the state.
* @category State
*/
export function getBodies(state: State): CelestialBody[] {
return state.bodies;
}
Loading

0 comments on commit ba77a2f

Please sign in to comment.