/**
* Name: Perfect Gas
* Author: Arnaud Grignard - Alexis Drogoul 2021
* Description: This is a model that shows how the physics engine works with and without gravity. Particles, provided with an initial impulse,
* collide each other and the walls. Without gravity and friction, and with a perfect restitution, this movement can go on forever.
* The user can apply gravity or not, as well as remove one (or several) of the walls to alter this behavior.
* Tags: physics_engine, skill, 3d, spatial_computation
*/
model Gas

/**
 * The model is inheriting from 'physical_world' a special model species that provides access to the physics engine -- and the possibility
 * to manage physical agents. In this model, the world itself is not a physical agent
 */
global parent: physical_world {
	bool use_native <- true;
	int width parameter: 'Dimensions' init:500 ; 
	point gravity <- {0.0, 0.0, 0.0};
	bool withGravity <- false parameter: "Enable gravity" on_change: {gravity <- withGravity ? {0.0, 0.0, -9.81} : {0.0, 0.0, 0.0};};
	bool accurate_collision_detection <- false parameter: "Finer collision detection";
	bool show_walls <- true parameter: "Show walls";
	geometry shape <- rectangle(width, width);
	float step <- 0.01;
 
	init {
		//10000 particles are created, randomly located in a virtual box in the center of the world
		create particles number: 10000 {
			location <-  {rnd(width/2) + width/4,rnd(width/2) + width/4,rnd(width/2)  + width/4};
		}
		//We create walls, large boxes that prevent the particles from moving outside
		create wall from: [box(width, 3*width, width) at_location {-width/2, width/2, 0},box(width, 3*width, width) at_location {3*width/2, width/2, 0},box(width, width, width) at_location {width/2, -width/2, 0},box(width, width, width) at_location {width/2, 3*width/2,  0}];
		create wall from: [box({3*width,3*width, width}) at_location {width/2,width/2,width}, box({3*width,3*width, width}) at_location {width/2,width/2, -width}];
	}	

} 


/**
 * The walls are static physical bodies that offer no friction or restitution whatsoever.
 */
species wall skills: [static_body]{
	float friction <- 0.0;
	float restitution <- 1.0;
    aspect default {
		if (show_walls) {draw shape color: #black wireframe:true;}
	}
}
 	
/**
 * Particles are dynamic bodies that wander around. They provide a perfect restitution (i.e. bounciness) and no friction.
 */
species particles skills: [dynamic_body] {  
	geometry shape <- sphere(2);
	rgb color <- one_of(brewer_colors("Greens"));
	// No friction exerted on other particles
	float friction <- 0.0;
	// No damping, which woud slow down their move
	float damping <- 0.0;
	float angular_damping <- 0.0;
	// Perfect restitution ('bouncing')
	float restitution <- 1.0;	
	
	// An initial velocity is provided to the agents
	init {
		float amp <-100.0;
	    velocity <- {rnd(amp) - amp/2, rnd(amp) - amp/2, rnd(amp) - amp/2};
	}
	
	// A (commented out) callback action can be defined, for instance to exchange the colors of the particles when they collide
//	action contact_added_with(agent other) {
//		if (other is particles) {
//			color <- particles(other).color;
//		}
// 	}
}


experiment "Gas Chamber" type: gui {
	
	// Allows to play with the step of the simulation (and physics step)
	parameter "Physics resolution step (in sec)" var: step min: 0.0001 max: 1.0 ;
	// With this command, the user can destroy one of the walls at random
	user_command "Open one wall" color: #red {
		ask (one_of(wall)) {
			do die;
		}
	}
	output {
		display Cube type:opengl background:#white axes:false camera: "1" {
			camera "1" location: {236.9814,1275.9964,799.6291} target: {250.0,250.0,150.0};
			camera "2" location: {236.9814,-1275.9964,799.6291} target: {250.0,250.0,150.0};
			species wall;
	    	species particles {draw shape color: color;}			
		}
	}
}