Water Clock Sim v3 (#1668)

* Added Water Clock Sim

* Updated graphics and documentation

* Added images for README

* Typos in README

---------

Co-authored-by: Pherring04 <plherrin@JSLRL0523040929.ndc.nasa.gov>
This commit is contained in:
Pherring04 2024-04-18 11:24:02 -05:00 committed by GitHub
parent 04822023de
commit e515144252
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 1617 additions and 0 deletions

View File

@ -0,0 +1,37 @@
global DR_GROUP_ID
global drg
try:
if DR_GROUP_ID >= 0:
DR_GROUP_ID += 1
except NameError:
DR_GROUP_ID = 0
drg = []
drg.append(trick.DRAscii("WaterClock"))
drg[DR_GROUP_ID].set_freq(trick.DR_Always)
drg[DR_GROUP_ID].set_cycle(0.01)
drg[DR_GROUP_ID].set_single_prec_only(False)
drg[DR_GROUP_ID].add_variable("dyn.waterclock.time")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.input_flow")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_clock_spout_flowrate")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_overflow_flowrate")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_bucket_net_flow")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_bucket_depth")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_bucket_diam")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_overflow_height")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_overflow_diameter")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_clock_spout_height")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_clock_spout_diameter")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.timer_bucket_depth")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.timer_bucket_diam")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_bucket_vol")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.intake_water_level")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.timer_bucket_vol")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.timer_water_level")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.tick_gap")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.total_ticks")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.current_tick")
drg[DR_GROUP_ID].add_variable("dyn.waterclock.gravity")
drg[DR_GROUP_ID].set_max_file_size(1 * 1073741824) # multiply converts GiB to B --Dr. Dre
trick.add_data_record_group(drg[DR_GROUP_ID], trick.DR_Buffer)
drg[DR_GROUP_ID].enable()

View File

@ -0,0 +1,62 @@
# SIM_WaterClock
---
SIM_WaterClock simulates a simple water clock. A water clock is a clock that measures time utilizing the flow of water. There exists different designs for water clocks, but this one uses a basic two bucket design.
The first bucket is called the intake bucket. The intake bucket receives water from an external source of variable flow rate. In the real world this might be piped in from a stream for example. In this sim, the water source (input_flow) is a variable range from 0 to 10 liters/s that can be arbitrarily adjusted via the GUI. The intake bucket contains two spouts, a clock spout and an overflow spout. Both spouts are cylinders defined by their width and height on the intake bucket. The clock spout pours water into the second bucket (timer bucket), while the overflow spout empties water into the void.
In an ideal water clock, by balancing the dimensions of the intake bucket, the clock spout, overflow spout, and the input flow rate, the flow rate of the clock spout (and therefore the input flow rate of the timer bucket) will be constant. Given a constant flow rate into the timer bucket, we can correlate water level with time passed.
Assumptions:
* For the purpose of determining if a pipe is submerged, the pipe will be treated as a single point at its center.
* When the timing bucket is filled, a magical siphon will drain it instaneously. This prevents the need to simulate the recalibration of the clock.
* Buckets and spouts are perfectly cylindrical.
### A Brief History
The water clock (or clepsydra to the ancient Greek) is a device used to measure time through the displacement of water. It is not known precisely when the earliest water clocks were developed, but they have been discovered to exist in various parts of the world as early as the 16th century BC. These early designs were relatively simple compared to later designs, consiting of a bowl with markings to indicate time passing as the bowl either filled or drained.
Water clocks remained a prominent timekeeping device until the 17th century when better methods of timekeeping were developed. Over those many centruies, different cultures innovated on the design of the early water clocks. Of particular note were the contributions of the Greek inventor Ctesibius in the 3rd century BC. Ctesibius innovated on the water clock by making it largely automatic. Prior to Ctesibius, water clocks needed to be consistently refilled/emptied by hand. Furthermore, if a water clock had indicators marking the position of the sun, they would need to be manually adjusted for different seasons. Ctesibius automated both these processes.
Ctesibius automated the draining process with a siphon akin to a Pythagorean cup. This siphon would empty over a water wheel, which powered a series of gears that would turn a cylinder. The cylinder had a row of irregular rings drawn around it, meant to correlate with the position of the sun throughout the seasons. Each day, as the water clock would fill it would accurately indicate the position of the sun, drain itself at the end of the day, and adjust the cylinder to be accurate for the next day.
### Building the Simulation
After building trick, in the SIM\_waterclock directory run the command **trick-CP** to build the sim. When it's complete, you should see:
```
Trick Build Process Complete
```
To build the graphics client **cd** into models/graphics/ and run **mvn package**. This isn't necessary for the sim to run, but will provide a visual display of the water clock.
### Running the Simulation
In the SIM_waterclock directory:
```
% S_main_*.exe RUN_test/input.py
```
The Sim Control Panel, and a GUI called "Water Clock" should appear.
![Water Clock graphics client at the start of a run.](WaterClockStart.png)
Click the Start on the Trick Sim Control Panel. The Water Clock should begin to fill up.
![Water Clock graphics client mid-run.](WaterClockRunning.png)
The only control on the GUI client is a slider which changes the flow rate of water into the water clock. It can be set anywhere from no flow up to 10 liters per second (10,000 cm^3^/s).
By default, the water clock will count out 60 "ticks" at a little over 1 second a tick. See if you can clibrate the water clock to count out a proper minute (1 second a tick).
### Configurable Parameters
The following parameters are meant to be configured by the user. They consist of the dimensions of the buckets, the dimensions and placement of the intake bucket spouts, and the number of time ticks.
Variable | Type | Units
----------------------------------------------------------------------|----------------|-------
dyn.waterclock.intake_bucket_depth | double | m
dyn.waterclock.intake_bucket_diam | double | m
dyn.waterclock.intake_overflow_height | double | m
dyn.waterclock.intake_overflow_diameter | double | m
dyn.waterclock.intake_clock_spout_height | double | m
dyn.waterclock.intake_clock_spout_diameter | double | m
dyn.waterclock.timer_bucket_depth | double | m
dyn.waterclock.timer_bucket_diam | double | m
dyn.waterclock.total_ticks | int | --

View File

@ -0,0 +1,44 @@
exec(open("Modified_data/my_waterclock.dr").read())
trick.frame_log_on()
trick.real_time_enable()
trick.exec_set_software_frame(0.1)
trick.itimer_enable()
trick.exec_set_enable_freeze(True)
trick.exec_set_freeze_command(True)
trick.sim_control_panel_set_enabled(True)
dyn.waterclock.input_flow = 1000.0
dyn.waterclock.intake_bucket_depth = 70.0
dyn.waterclock.intake_bucket_diam = 40.0
dyn.waterclock.intake_overflow_height = 60.0
dyn.waterclock.intake_overflow_diameter = 25.0
dyn.waterclock.intake_clock_spout_height = 15.0
dyn.waterclock.intake_clock_spout_diameter = 20.0
dyn.waterclock.timer_bucket_depth = 100.0
dyn.waterclock.timer_bucket_diam = 45.0
dyn.waterclock.total_ticks = 60
trick.message_unsubscribe(trick_message.mcout)
# ==========================================
# Start the Satellite Graphics Client
# ==========================================
varServerPort = trick.var_server_get_port();
WaterClockDisplay_path = "models/graphics/build/WaterClockDisplay.jar"
if (os.path.isfile(WaterClockDisplay_path)) :
WaterClockDisplay_cmd = "java -jar " \
+ WaterClockDisplay_path \
+ " " + str(varServerPort) + " &" ;
print(WaterClockDisplay_cmd)
os.system( WaterClockDisplay_cmd);
else :
print('==================================================================================')
print('Display needs to be built. Please \"cd\" into ../models/graphics and type \"mvn package\".')
print('==================================================================================')

View File

@ -0,0 +1,36 @@
/************************TRICK HEADER*************************
PURPOSE:
(S_define file for SIM_waterclock_numeric)
LIBRARY DEPENDENCIES:
(
(waterclock/src/waterclock_init.c)
(waterclock/src/waterclock_numeric.c)
(waterclock/src/waterclock_shutdown.c)
)
*************************************************************/
#include "sim_objects/default_trick_sys.sm"
##include "waterclock/include/waterclock_numeric.h"
class WaterClockSimObject : public Trick::SimObject {
public:
WATERCLOCK waterclock;
WaterClockSimObject() {
("default_data") waterclock_default_data( &waterclock ) ;
("initialization") waterclock_init( &waterclock ) ;
("derivative") waterclock_deriv( &waterclock ) ;
("integration") trick_ret= waterclock_integ( & waterclock ) ;
("shutdown") waterclock_shutdown( &waterclock ) ;
("dynamic_event") waterclock_tick_change( &waterclock ) ;
("dynamic_event") waterclock_overflow_timer( &waterclock ) ;
}
} ;
WaterClockSimObject dyn ;
IntegLoop dyn_integloop (0.01) dyn ;
void create_connections() {
dyn_integloop.getIntegrator(Runge_Kutta_4, 4);
}

View File

@ -0,0 +1,2 @@
TRICK_CFLAGS += -Imodels
TRICK_CXXFLAGS += -Imodels

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,6 @@
all:
mvn package
clean:
rm -rf build

View File

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>trick-java</groupId>
<artifactId>trick-java</artifactId>
<version>23.0.0-beta</version>
<name>trick-java</name>
<url>https://github.com/nasa/trick</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>WaterClockDisplay</finalName>
<directory>build</directory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
<destDir>../../share/doc/trick/java</destDir>
</configuration>
</plugin>
</plugins>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<compilerArgs>
<arg>-g</arg>
<arg>-Xlint:unchecked</arg>
<arg>-Xlint:deprecation</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>WaterClockDisplay</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<!--
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
-->
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -0,0 +1,779 @@
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.*;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.sound.sampled.*;
import java.net.URL;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.Font;
import javax.swing.text.NumberFormatter;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.border.EtchedBorder;
import java.awt.Component;
class ScenePoly {
public Color color;
public int n;
public double[] x;
public double[] y;
}
class RangeView extends JPanel {
private int scale;
private Color bucket_color;
private Color spout_color;
private Color water_color;
private Color float_color;
private Color clock_color;
private Color clock_display_color;
private Color tick_color;
private Color gear_color;
// Origin of world coordinates in jpanel coordinates.
private int worldOriginX;
private int worldOriginY;
private double spout_rate;
private double overflow_rate;
private double intake_depth;
private double timer_depth;
private double intake_lvl;
private double timer_lvl;
private double intake_vol;
private double timer_vol;
private double spout_height;
private double overflow_height;
private double input_flow;
private int current_tick;
private double clock_float_height;
// Controls
private double input_flow_select;
public boolean new_input_flow;
/**
* Class constructor.
*/
public RangeView( int mapScale) {
setScale(mapScale);
spout_rate = 0.0;
overflow_rate = 0.0;
intake_depth = 0.0;
timer_depth = 0.0;
intake_lvl = 0.0;
timer_lvl = 0.0;
intake_vol = 0.0;
timer_vol = 0.0;
spout_height = 0.0;
overflow_height = 0.0;
input_flow = 0.0;
input_flow_select = 0.0;
current_tick = 0;
new_input_flow = false;
bucket_color = new Color(150,75,0);
spout_color = new Color(128,128,128);
water_color = new Color(0,0,128);
float_color = new Color(0,0,0);
clock_color = new Color(204,204,0);
clock_display_color = new Color(192,192,192);
tick_color = new Color(0,0,0);
gear_color = new Color(128,128,128);
workPolyX = new int[150];
workPolyY = new int[150];
tooth = new ScenePoly();
tooth.color = float_color;
tooth.x = new double[] { 0, -0.15, -0.25 , -0.15 , 0 };
tooth.y = new double[] { 0, 0 , 0.075 , 0.15 , 0.15 };
tooth.n = 5;
clock_float_height = 8;
}
private ScenePoly gear;
private ScenePoly tooth;
private int[] workPolyX, workPolyY;
public void fillSceneRect(Graphics2D g2d, Color color, double x, double y, double w, double h) {
g2d.setPaint(color);
g2d.fillRect( (int)(worldOriginX+scale*(x)), (int)(worldOriginY-scale*(y)), (int)(scale*w), (int)(scale*h));
}
public void fillScenePoly(Graphics2D g, ScenePoly p, double angle_r , double x, double y) {
for (int ii = 0; ii < p.n; ii++) {
workPolyX[ii] = (int)(worldOriginX + scale *
( Math.cos(angle_r) * p.x[ii] - Math.sin(angle_r) * p.y[ii] + x));
workPolyY[ii] = (int)(worldOriginY - scale *
( Math.sin(angle_r) * p.x[ii] + Math.cos(angle_r) * p.y[ii] + y));
}
g.setPaint(p.color);
g.fillPolygon(workPolyX, workPolyY, p.n);
}
public void fillSceneOval(Graphics2D g2d, Color color, double x, double y, double w, double h) {
g2d.setPaint(color);
g2d.fillOval( (int)(worldOriginX+scale*(x-w/2)), (int)(worldOriginY-scale*(y+h/2)), (int)(scale*w), (int)(scale*h));
}
public void setSpoutRate(double x) {
spout_rate = x;
}
public void setOverflowRate(double x) {
overflow_rate = x;
}
public void setIntakeDepth(double x) {
intake_depth = x;
}
public void setTimerDepth(double x) {
timer_depth = x;
}
public void setIntakeWarerLevel(double x) {
intake_lvl = x;
}
public void setTimerWarerLevel(double x) {
timer_lvl = x;
}
public void setIntakeWaterVol(double x) {
intake_vol = x;
}
public void setTimerWaterLevel(double x) {
timer_vol = x;
}
public void setSpoutHeight(double x) {
spout_height = x;
}
public void setOverflowHeight(double x) {
overflow_height = x;
}
public void setInputFlow(double x) {
input_flow = x;
}
public void setInputFlowSelect(double x) {
input_flow_select = x;
}
public double getInputFlowSelect() {
return input_flow_select;
}
public void setCurrentTick(int x) {
current_tick = x;
}
public void setScale (int mapScale) {
if (mapScale < 2) {
scale = 2;
} else if (mapScale > 128) {
scale = 128;
} else {
scale = mapScale;
}
repaint();
}
private void doDrawing(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
int width = getWidth();
int height = getHeight();
worldOriginX = (width/2) - (int)(scale * 0);
worldOriginY = (height/2) + (int)(scale * 0);
// Draw intake Bucket
double bucket_length = 2.0;
double bucket_width = 0.15;
double intake_bucket_origin_x = 4;
double intake_bucket_origin_y = 1.7;
double intake_bucket_left_wall_x = intake_bucket_origin_x - bucket_length - bucket_width;
double intake_bucket_bottom_x = intake_bucket_origin_x - bucket_length - bucket_width;
double intake_bucket_bottom_y = intake_bucket_origin_y - bucket_length;
double spout_width = 0.175;
double spout_length = 1.0;
double spout_pipe_x = intake_bucket_left_wall_x - spout_length + bucket_width;
double spout_pipe_y = intake_bucket_origin_y - bucket_length + spout_width + ((spout_height / intake_depth) * bucket_length) - spout_width/2;
double overflow_pipe_x = intake_bucket_origin_x;
double overflow_pipe_y = intake_bucket_origin_y - bucket_length + spout_width + ((overflow_height / intake_depth) * bucket_length) - spout_width/2;
fillSceneRect( g2d,
bucket_color,
intake_bucket_origin_x,
intake_bucket_origin_y,
bucket_width,
bucket_length);
fillSceneRect( g2d,
bucket_color,
intake_bucket_bottom_x,
intake_bucket_bottom_y,
bucket_length + (2 * bucket_width),
bucket_width);
fillSceneRect( g2d,
bucket_color,
intake_bucket_left_wall_x,
intake_bucket_origin_y,
bucket_width,
bucket_length);
fillSceneRect( g2d,
spout_color,
overflow_pipe_x,
overflow_pipe_y,
spout_length,
spout_width);
fillSceneRect( g2d,
spout_color,
spout_pipe_x,
spout_pipe_y,
spout_length,
spout_width);
//Draw timer bucket
double timer_bucket_origin_x = 1.3;
double timer_bucket_origin_y = -0.5;
double timer_bucket_left_wall_x = timer_bucket_origin_x - bucket_length - bucket_width;
double timer_bucket_bottom_x = timer_bucket_origin_x - bucket_length - bucket_width;
double timer_bucket_bottom_y = timer_bucket_origin_y - bucket_length;
fillSceneRect( g2d,
bucket_color,
timer_bucket_origin_x,
timer_bucket_origin_y,
bucket_width,
bucket_length);
fillSceneRect( g2d,
bucket_color,
timer_bucket_bottom_x,
timer_bucket_bottom_y,
bucket_length + (2 * bucket_width),
bucket_width);
fillSceneRect( g2d,
bucket_color,
timer_bucket_left_wall_x,
timer_bucket_origin_y,
bucket_width,
bucket_length);
//Draw water flow
double flow_width = 0.15;
double spout_flow_height = intake_bucket_origin_y - timer_bucket_origin_y + (bucket_length - (intake_bucket_origin_y - spout_pipe_y)) - spout_width/2;
double overflow_height = 20;
if (spout_rate != 0.0) {
fillSceneRect( g2d,
water_color,
intake_bucket_left_wall_x - spout_length + bucket_width - flow_width + 0.015,
spout_pipe_y - spout_width/2,
flow_width,
spout_flow_height);
}
if (overflow_rate != 0.0) {
fillSceneRect( g2d,
water_color,
intake_bucket_origin_x + spout_length,
overflow_pipe_y - spout_width/2,
flow_width,
overflow_height);
}
//Draw water level
double intake_capacity = intake_lvl / intake_depth;
double intake_offset = ((1 - intake_capacity) * bucket_length) ;
double timer_capacity = timer_lvl / timer_depth;
double timer_offset = ((1 - timer_capacity) * bucket_length) ;
fillSceneRect( g2d,
water_color,
intake_bucket_origin_x - bucket_length - 0.01,
intake_bucket_origin_y - intake_offset,
bucket_length + 0.03,
intake_capacity * bucket_length);
//fill in pixel gaps due to rounding error
if(intake_lvl > 0.0) {
fillSceneRect( g2d,
water_color,
intake_bucket_origin_x - bucket_length - 0.01,
intake_bucket_origin_y - bucket_length + 0.05,
bucket_length + 0.03,
0.05);
}
fillSceneRect( g2d,
water_color,
timer_bucket_origin_x - bucket_length - 0.01,
timer_bucket_origin_y - timer_offset,
bucket_length + 0.03,
timer_capacity * bucket_length);
//fill in pixel gaps due to rounding error
if(timer_lvl > 0.0) {
fillSceneRect( g2d,
water_color,
timer_bucket_origin_x - bucket_length - 0.01,
timer_bucket_origin_y - bucket_length + 0.05,
bucket_length + 0.03,
0.075);
}
//Draw external source pipe
fillSceneRect( g2d,
spout_color,
intake_bucket_origin_x - bucket_length/4,
intake_bucket_origin_y + 0.8,
7,
spout_width);
if(input_flow > 0) {
fillSceneRect( g2d,
water_color,
intake_bucket_origin_x - bucket_length/4 - flow_width + 0.03,
intake_bucket_origin_y + 0.8 - spout_width/2,
flow_width,
0.815 + bucket_length - spout_width/2);
}
//Draw float
double float_base_height = 0.25;
fillSceneRect( g2d,
float_color,
timer_bucket_origin_x - bucket_length + bucket_length/4,
timer_bucket_origin_y - timer_offset + float_base_height,
bucket_length/2,
0.25);
double float_arm_origin_x = timer_bucket_origin_x - bucket_length + bucket_length * 0.45;
double float_arm_origin_y = timer_bucket_origin_y - timer_offset + clock_float_height + float_base_height;
fillSceneRect( g2d,
float_color,
float_arm_origin_x,
float_arm_origin_y,
bucket_length*0.1,
clock_float_height);
double tooth_ratio = 2.25 * tooth.y[3];
for(double ii = bucket_length/2.0; ii < (clock_float_height) ; ii += tooth_ratio) {
fillScenePoly(g2d, tooth, 0.0, float_arm_origin_x, ii + float_arm_origin_y - clock_float_height);
}
//Draw Gear
double clock_origin_x = float_arm_origin_x - 1.85;
double clock_origin_y = 2.0;
double clock_diam = 2.5;
double gear_x = clock_origin_x + 0.85;
double gear_y = clock_origin_y;
double gear_width = 1.5;
double gear_noise = 0.3; //initial gear rotational offset
gear = new ScenePoly();
gear.x = new double[] { 0, 0, 0, 0, 0};
gear.y = new double[] { 0, 0, 0, 0, 0};
gear.n = 5;
for(int ii = 0; ii < gear.n; ++ii) {
gear.x[ii] = tooth.x[ii]-(gear_width*0.5);
gear.y[ii] = tooth.y[ii];
}
gear.n = 5;
double gear_circ = (Math.PI * (gear_width - (2*tooth.x[2])));
int gear_count = (int)(gear_circ / tooth_ratio);
double gear_offset = ((timer_capacity * bucket_length) / gear_circ) * 2 * Math.PI;
gear_offset *= 3; //I don't know why, but this magic number makes the gear animation sync with the rack
gear.color = gear_color;
for(int ii = 0; ii < gear_count; ++ii) {
fillScenePoly(g2d, gear, (ii + gear_noise + gear_offset) * (360/gear_count) * (Math.PI/180), gear_x, gear_y);
}
fillSceneOval ( g2d,
gear_color,
gear_x,
gear_y,
gear_width*1.05,
gear_width*1.05);
//Draw Clock
fillSceneOval ( g2d,
clock_color,
clock_origin_x,
clock_origin_y,
clock_diam,
clock_diam);
double clock_display_length = 1.0;
double clock_display_origin_x = clock_origin_x - clock_display_length/2.0;
double clock_display_origin_y = clock_origin_y;
fillSceneRect( g2d,
clock_display_color,
clock_display_origin_x,
clock_display_origin_y,
clock_display_length,
clock_display_length);
g2d.setFont(new Font("", Font.PLAIN, 24));
g2d.setPaint(tick_color);
g2d.drawString ( String.format("%02d",current_tick), (int)(worldOriginX+scale*(clock_display_origin_x + clock_display_length*0.25)), (int)(worldOriginY-scale*(clock_display_origin_y - clock_display_length*0.6)));
// Draw Information
g2d.setPaint(Color.BLACK);
g2d.setFont(new Font("", Font.PLAIN, 12));
int string_height = 220;
g2d.drawString ( String.format("Input Flow Rate: [%.4f] cm^3/s",input_flow), 20,string_height+=20);
g2d.drawString ( String.format("Intake Water Level: [%.4f] cm",intake_lvl), 20,string_height+=20);
g2d.drawString ( String.format("Intake Water Volume: [%.4f] cm^3",intake_vol), 20,string_height+=20);
g2d.drawString ( String.format("Intake Overflow Rate: [%.4f] cm^3/s",overflow_rate), 20,string_height+=20);
g2d.drawString ( String.format("Intake Spout Rate: [%.4f] cm^3/s",spout_rate), 20,string_height+=20);
g2d.drawString ( String.format("Timer Water Level: [%.4f] cm",timer_lvl), 20,string_height+=20);
g2d.drawString ( String.format("Timer Water Volume: [%.4f] cm^3",timer_vol), 20,string_height+=20);
g2d.drawString ( String.format("Current Time Tick: [%d]",current_tick), 20,string_height+=20);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
}
class TrickSimMode {
public static final int INIT = 0;
public static final int FREEZE = 1;
public static final int RUN = 5;
}
class InputFlowCtrlPanel extends JPanel implements ChangeListener {
static final int FLOW_MIN = 0;
static final int FLOW_MAX = 10000;
static final int FLOW_INIT = 1000;
private RangeView rangeView;
private JSlider inputFlowSlider;
public InputFlowCtrlPanel (RangeView view) {
rangeView = view;
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
JLabel sliderLabel = new JLabel("", JLabel.CENTER);
sliderLabel.setAlignmentX(CENTER_ALIGNMENT);
inputFlowSlider = new JSlider(JSlider.HORIZONTAL, FLOW_MIN, FLOW_MAX, FLOW_INIT);
inputFlowSlider.addChangeListener(this);
inputFlowSlider.setToolTipText("Input Flow Rate (cm^3/s).");
inputFlowSlider.setMajorTickSpacing(1000);
inputFlowSlider.setMinorTickSpacing(100);
inputFlowSlider.setPaintTicks(true);
inputFlowSlider.setPaintLabels(true);
add(sliderLabel);
add(inputFlowSlider);
}
@Override
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
rangeView.setInputFlowSelect( source.getValue());
rangeView.new_input_flow = true;
}
}
public void setValue(int value) {
if (value > FLOW_MAX) value = FLOW_MAX;
if (value < FLOW_MIN) value = FLOW_MIN;
inputFlowSlider.setValue(value);
}
}
class ControlPanel extends JPanel implements ActionListener {
private RangeView rangeView;
private InputFlowCtrlPanel inputFlowCtrlPanel;
public ControlPanel(RangeView view) {
rangeView = view;
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
JPanel labeledInputFlowCtrlPanel = new JPanel();
labeledInputFlowCtrlPanel.setLayout(new BoxLayout(labeledInputFlowCtrlPanel, BoxLayout.Y_AXIS));
JLabel inputFlowCtrlLabel = new JLabel("Input Flow Rate (cm^3/s)");
inputFlowCtrlLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
labeledInputFlowCtrlPanel.add(inputFlowCtrlLabel);
inputFlowCtrlPanel = new InputFlowCtrlPanel(rangeView);
labeledInputFlowCtrlPanel.add( inputFlowCtrlPanel );
add(labeledInputFlowCtrlPanel);
}
public void actionPerformed(ActionEvent e) {
String s = e.getActionCommand();
switch (s) {
default:
System.out.println("Unknown Action Command:" + s);
break;
}
}
} // class ControlPanel
public class WaterClockDisplay extends JFrame {
private RangeView rangeView;
private BufferedReader in;
private DataOutputStream out;
private JPanel panelGroup0;
private JPanel panelGroup1;
private ControlPanel controlPanel;
public WaterClockDisplay(RangeView arena) {
setTitle("Water Clock");
rangeView = arena;
panelGroup1 = new JPanel();
panelGroup1.setLayout(new BoxLayout(panelGroup1, BoxLayout.X_AXIS));
panelGroup1.add(rangeView);
controlPanel = new ControlPanel(rangeView);
panelGroup0 = new JPanel();
panelGroup0.setLayout(new BoxLayout(panelGroup0, BoxLayout.Y_AXIS));
panelGroup0.add(panelGroup1);
panelGroup0.add(controlPanel);
add(panelGroup0);
rangeView.setScale(64);
setSize(800, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setFocusable(true);
}
public void connectToServer(String host, int port ) throws IOException {
Socket socket = new Socket(host, port);
in = new BufferedReader( new InputStreamReader( socket.getInputStream()));
out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
}
public void drawRangeView() {
rangeView.repaint();
}
private static void printHelpText() {
System.out.println(
"----------------------------------------------------------------------\n"
+ "usage: java jar WaterClockDisplay.jar <port-number>\n"
+ "----------------------------------------------------------------------\n"
);
}
public enum ModelState { INACTIVE, READY, ACTIVE }
public static void main(String[] args) throws IOException, InterruptedException {
String host = "localHost";
int port = 0;
boolean boom = false;
int ii = 0;
while (ii < args.length) {
switch (args[ii]) {
case "-help" :
case "--help" : {
printHelpText();
System.exit(0);
} break;
default : {
port = (Integer.parseInt(args[ii]));
} break;
}
++ii;
}
boolean go = true;
double dt = 0.100; // Time between updates (seconds).
double spout_rate = 0.0;
double overflow_rate = 0.0;
double intake_depth = 0.0;
double timer_depth = 0.0;
double intake_lvl = 0.0;
double timer_lvl = 0.0;
double intake_vol = 0.0;
double timer_vol = 0.0;
double spout_height = 0.0;
double overflow_height = 0.0;
double input_flow = 0.0;
double flow_select = 0.0;
int tick = 0;
// Outbound command variables
int simMode = 0;
boolean standalone = false;
int mapScale = 32 ; // pixels per meter.
RangeView rangeView = new RangeView( mapScale);
WaterClockDisplay waterClockDisplay = new WaterClockDisplay( rangeView);
waterClockDisplay.setVisible(true);
waterClockDisplay.drawRangeView();
if (go) {
if (port == 0) {
System.out.println("No variable server port specified.");
printHelpText();
System.exit(0);
}
// Connect to the Trick simulation's variable server
System.out.println("Connecting to: " + host + ":" + port);
waterClockDisplay.connectToServer(host, port);
waterClockDisplay.out.writeBytes("trick.var_set_client_tag(\"WaterClockDisplay\") \n");
waterClockDisplay.out.flush();
// Have the Variable Server send us the simulation mode ONCE.
waterClockDisplay.out.writeBytes( "trick.var_add(\"trick_sys.sched.mode\")\n" +
"trick.var_send() \n" +
"trick.var_clear() \n");
waterClockDisplay.out.flush();
// Read the response and extract the simulation mode.
try {
String line;
String field[];
line = waterClockDisplay.in.readLine();
field = line.split("\t");
simMode = Integer.parseInt( field[1]);
} catch (IOException | NullPointerException e ) {
go = false;
}
// Configure the Variable Server to cyclically send us the following varibales.
// Tell the variable server:
// 1) We want the values of the following variables:
waterClockDisplay.out.writeBytes( "trick.var_pause() \n" +
"trick.var_add(\"dyn.waterclock.intake_clock_spout_flowrate\")\n" +
"trick.var_add(\"dyn.waterclock.intake_overflow_flowrate\")\n" +
"trick.var_add(\"dyn.waterclock.intake_bucket_depth\")\n" +
"trick.var_add(\"dyn.waterclock.timer_bucket_depth\")\n" +
"trick.var_add(\"dyn.waterclock.intake_water_level\")\n" +
"trick.var_add(\"dyn.waterclock.timer_water_level\")\n" +
"trick.var_add(\"dyn.waterclock.intake_bucket_vol\")\n" +
"trick.var_add(\"dyn.waterclock.timer_bucket_vol\")\n" +
"trick.var_add(\"dyn.waterclock.intake_clock_spout_height\")\n" +
"trick.var_add(\"dyn.waterclock.intake_overflow_height\")\n" +
"trick.var_add(\"dyn.waterclock.input_flow\")\n" +
"trick.var_add(\"dyn.waterclock.current_tick\")\n" +
"trick.var_add(\"trick_sys.sched.mode\")\n" +
// 2) We want the responses in ASCII:
"trick.var_ascii() \n" +
// 3) We want values to be updated at the specified rate:
String.format("trick.var_cycle(%.3f)\n", dt) +
// 4) Start sending values as specified.
"trick.var_unpause() \n" );
waterClockDisplay.out.flush();
} // if go
while (go) {
// Recieve and parse periodic data response from the variable server.
try {
String line;
String field[];
line = waterClockDisplay.in.readLine();
field = line.split("\t");
spout_rate = Double.parseDouble( field[1]);
overflow_rate = Double.parseDouble( field[2]);
intake_depth = Double.parseDouble( field[3]);
timer_depth = Double.parseDouble( field[4]);
intake_lvl = Double.parseDouble( field[5]);
timer_lvl = Double.parseDouble( field[6]);
intake_vol = Double.parseDouble( field[7]);
timer_vol = Double.parseDouble( field[8]);
spout_height = Double.parseDouble( field[9]);
overflow_height = Double.parseDouble( field[10]);
input_flow = Double.parseDouble( field[11]);
tick = Integer.parseInt( field[12]);
simMode = Integer.parseInt( field[13]);
} catch (IOException | NullPointerException e ) {
go = false;
}
// Update the display data.
rangeView.setSpoutRate(spout_rate);
rangeView.setOverflowRate(overflow_rate);
rangeView.setIntakeDepth(intake_depth);
rangeView.setTimerDepth(timer_depth);
rangeView.setIntakeWarerLevel(intake_lvl);
rangeView.setTimerWarerLevel(timer_lvl);
rangeView.setIntakeWaterVol(intake_vol);
rangeView.setTimerWaterLevel(timer_vol);
rangeView.setSpoutHeight(spout_height);
rangeView.setOverflowHeight(overflow_height);
rangeView.setInputFlow(input_flow);
rangeView.setCurrentTick(tick);
if(rangeView.new_input_flow) {
flow_select = rangeView.getInputFlowSelect();
waterClockDisplay.out.writeBytes( String.format("dyn.waterclock.input_flow = %f ;\n", flow_select ));
rangeView.new_input_flow = false;
}
waterClockDisplay.out.flush();
// Update the scene.
waterClockDisplay.drawRangeView();
} // while
} // main
} // class

View File

@ -0,0 +1,76 @@
/*************************************************************************
PURPOSE: (Represent the state and initial conditions of the water clock)
**************************************************************************/
#ifndef WATERCLOCK_H
#define WATERCLOCK_H
#include "trick/regula_falsi.h"
typedef struct {
//////////////////////////
/* ASSUMPTIONS
* 1) For the purpose of determining if a pipe is submerged, it will be treated as a single point at the center of the pipe
* 2) When the timing bucket is filled, a siphon will drain it instaneously
* 3) Buckets are cylindrical
*/
/* DESCRIPTION
* This is a simulation of a simple water clock. The clock consists of two cylinders (buckets).
* The first bucket is known as the intake bucket. It receives water from an unspecified external source (like a stream).
* The intake bucket has two cylindrical spouts extending from its sides, one known as an overflow spout and the other the clock spout.
* The overflow spout is simply for maintaing an equilibrium of the water level. It keeps the intake bucket from exceeding a certain water level, thus ensuring it's water level is consistent.
* The clock spout pours water into the second bucket (timer bucket). In an ideal clock, the water level of the intake bucket will remain consistent, meaning the clock spout will output at a constant rate and operate as an accurate clock.
* The timer bucket receives water from the clock spout. The timer bucket has no spouts, it fills until it is full, upon which a siphon instantaneously drains it.
* There exists a float in the timer bucket, connected to an arrow which will point to vertical tick marks. As the timer bucket fills, the arrow will move vertically along these ticks, indicating how much time has passed.
* Depending on the configuration of the clock (size of the buckets, size of the spouts, external water source rate, and the number/spacing of ticks) you can create a clock that tracks a variety of times.
*/
double time; /* s Model time */
double input_flow; /* cm^3/s Flow rate of the external water source to the water clock */
double intake_clock_spout_flowrate; /* cm^3/s Intake bucket output spout pipe flow rate */
double intake_overflow_flowrate; /* cm^3/s Intake bucket overflow pipe flow rate */
double intake_bucket_net_flow; /* cm^3/s Intake bucket net flow rate */
double intake_bucket_depth; /* cm Intake bucket depth */
double intake_bucket_diam; /* cm Intake bucket diameter */
double intake_overflow_height; /* cm Intake bucket overflow pipe height of center */
double intake_overflow_diameter; /* cm Intake bucket overflow pipe diameter */
double intake_clock_spout_height; /* cm Intake bucket output spout pipe height of center */
double intake_clock_spout_diameter; /* cm Intake bucket output spout pipe diameter */
double timer_bucket_depth; /* cm Timer bucket depth */
double timer_bucket_diam; /* cm Timer bucket diameter */
double intake_bucket_vol; /* cm^3 Intake bucket water volume */
double intake_water_level; /* cm Intake bucket water level */
double timer_bucket_vol; /* cm^3 Timer bucket water volume */
double timer_water_level; /* cm Timer bucket water level */
double tick_gap; /* cm Distance between tick marks */
int total_ticks; /* -- Total number of ticks on the timer */
int current_tick; /* -- The current timer tick to have crossed the threshold*/
double gravity; /* m/s^2 Gravity constant */
REGULA_FALSI rf1 ;
REGULA_FALSI rf2 ;
} WATERCLOCK ;
#ifdef __cplusplus
extern "C" {
#endif
int waterclock_default_data(WATERCLOCK*) ;
int waterclock_init(WATERCLOCK*) ;
int waterclock_shutdown(WATERCLOCK*) ;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,21 @@
/*************************************************************************
PURPOSE: ( Water Clock Numeric Model )
**************************************************************************/
#ifndef WATRERCLOCK_NUMERIC_H
#define WATERCLOCK_NUMERIC_H
#include "waterclock.h"
#ifdef __cplusplus
extern "C" {
#endif
int waterclock_integ(WATERCLOCK*);
int waterclock_deriv(WATERCLOCK*);
double waterclock_tick_change(WATERCLOCK*);
double waterclock_overflow_timer(WATERCLOCK*);
void waterclock_update_water_level(WATERCLOCK* WC);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,59 @@
/******************************* TRICK HEADER ****************************
PURPOSE: (Set the initial data values)
*************************************************************************/
/* Model Include files */
#include <math.h>
#include "../include/waterclock.h"
/* default data job */
int waterclock_default_data( WATERCLOCK* WC ) {
WC->time = 0.0 ;
WC->input_flow = 1000;
WC->intake_clock_spout_flowrate = 0.0;
WC->intake_overflow_flowrate = 0.0;
WC->intake_bucket_depth = 100.0;
WC->intake_bucket_diam = 500.0;
WC->intake_overflow_height = 080.0 * WC->intake_bucket_depth;
WC->intake_overflow_diameter = 100.0;
WC->intake_clock_spout_height = 010.0;
WC->intake_clock_spout_diameter = 005.0;
WC->timer_bucket_depth = 120.0;
WC->timer_bucket_diam = 050.0;
WC->intake_bucket_vol = 0.0;
WC->timer_bucket_vol = 0.0;
WC->total_ticks = 5;
WC->current_tick = 0;
WC->gravity = 9.81;
return 0 ;
}
/* initialization job */
int waterclock_init( WATERCLOCK* WC) {
if (WC->intake_overflow_height > WC->intake_bucket_depth) {
WC->intake_overflow_height = WC->intake_bucket_depth;
}
if (WC->intake_clock_spout_height > WC->intake_bucket_depth) {
WC->intake_clock_spout_height = WC->intake_bucket_depth;
}
if (WC->intake_overflow_height < 0) {
WC->intake_overflow_height = 0;
}
if (WC->intake_clock_spout_height < 0) {
WC->intake_clock_spout_height = 0;
}
WC->tick_gap = WC->timer_bucket_depth / WC->total_ticks ;
return 0 ;
}

View File

@ -0,0 +1,124 @@
/*********************************************************************
PURPOSE: ( Trick numeric )
*********************************************************************/
#include <stddef.h>
#include <stdio.h>
#include <math.h>
#include "trick/integrator_c_intf.h"
#include "../include/waterclock_numeric.h"
#include "trick/exec_proto.h"
#include "trick/message_proto.h"
#include <math.h>
int waterclock_deriv(WATERCLOCK* WC) {
//Make sure water level is up to date
waterclock_update_water_level(WC);
//Clock spout area
double spout_radius = WC->intake_clock_spout_diameter / 2;
double spout_area = M_PI * spout_radius * spout_radius;
//Overflow spout area
double overflow_radius = WC->intake_overflow_diameter / 2;
double overflow_area = M_PI * overflow_radius * overflow_radius;
//Calculate flow rate using Torricelli's equation ( V = sqrt(2gh) ) to find water velocity. Multiple velocity by spout area to find flow rate.
//Calculate input bucket spout flow rate.
if(WC->intake_water_level > WC->intake_clock_spout_height)
WC->intake_clock_spout_flowrate = spout_area * sqrt(2 * WC->gravity * (WC->intake_water_level - WC->intake_clock_spout_height) );
else
WC->intake_clock_spout_flowrate = 0.0;
//Calculate input bucket over flow rate
if(WC->intake_water_level > WC->intake_overflow_height)
WC->intake_overflow_flowrate = overflow_area * sqrt(2 * WC->gravity * (WC->intake_water_level - WC->intake_overflow_height) );
else
WC->intake_overflow_flowrate = 0.0;
//Need to know net flow of the source, overflow spout, and clock spout for integration
WC->intake_bucket_net_flow = WC->input_flow - WC->intake_clock_spout_flowrate - WC->intake_overflow_flowrate;
return(0);
}
int waterclock_integ(WATERCLOCK* WC) {
int ipass;
load_state(
&WC->intake_bucket_vol,
&WC->timer_bucket_vol,
NULL);
load_deriv(
&WC->intake_bucket_net_flow,
&WC->intake_clock_spout_flowrate,
NULL);
ipass = integrate();
unload_state(
&WC->intake_bucket_vol,
&WC->timer_bucket_vol,
NULL );
waterclock_update_water_level(WC);
return(ipass);
}
//Since we are inetgrating over water volume, we must convert volume to water level in order to track how quickly the timer bucket is filling up.
void waterclock_update_water_level(WATERCLOCK* WC)
{
//Calculate Input bucket water level
double intake_bucket_radius = WC->intake_bucket_diam / 2;
double intake_bucket_base = M_PI * intake_bucket_radius * intake_bucket_radius;
WC->intake_water_level = WC->intake_bucket_vol / intake_bucket_base;
//Calculate Timer bucket water level
double timer_bucket_radius = WC->timer_bucket_diam / 2;
double timer_bucket_base = M_PI * timer_bucket_radius * timer_bucket_radius;
WC->timer_water_level = WC->timer_bucket_vol / timer_bucket_base;
}
//When timer bucket fills, drain it instantly (we have a magic siphon)
double waterclock_overflow_timer( WATERCLOCK* WC ) {
double tgo;
double now;
WC->rf1.error = WC->timer_bucket_depth - WC->timer_water_level;
now = get_integ_time();
tgo = regula_falsi( now, &(WC->rf1) );
if (tgo == 0.0) {
now = get_integ_time() ;
reset_regula_falsi( now, &(WC->rf1) ) ;
WC->timer_water_level = 0; //Instantly drains
WC->timer_bucket_vol = 0; //Instantly drains
WC->current_tick = 0;
message_publish(MSG_NORMAL, "WATER CLOCK RESET\n" ) ;
}
return (tgo) ;
}
//Detect when the arrow has passed a new tick, print some diagnostics.
double waterclock_tick_change( WATERCLOCK* WC ) {
double tgo;
double now;
WC->rf2.error = WC->tick_gap - (WC->timer_water_level - ( WC->current_tick * WC->tick_gap ));
now = get_integ_time();
tgo = regula_falsi( now, &(WC->rf2) );
if (tgo == 0.0) {
now = get_integ_time() ;
reset_regula_falsi( now, &(WC->rf2) ) ;
if( (WC->current_tick < WC->total_ticks) && (WC->current_tick >= 0) )
{
WC->current_tick += 1;
message_publish(MSG_NORMAL, "Tick %d, Sim Time %f, Water Level %f\n", WC->current_tick, exec_get_sim_time(), WC->timer_water_level) ;
}
else
fprintf(stderr, "ERROR, SOMETHING WENT VERY WRONG!\n" ) ;
}
return (tgo) ;
}

View File

@ -0,0 +1,13 @@
/************************************************************************
PURPOSE: (Shutdown the sim)
*************************************************************************/
#include <stdio.h>
#include "../include/waterclock.h"
#include "trick/exec_proto.h"
int waterclock_shutdown( WATERCLOCK* WC) {
printf( "========================================\n");
printf( " Water Clock Shutdown \n");
printf( "========================================\n");
return 0 ;
}

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<trickView>
<cyclePeriod>0.5</cyclePeriod>
<variable>
<name>dyn.waterclock.intake_overflow_flowrate</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m^3/s</units>
</variable>
<variable>
<name>dyn.waterclock.intake_clock_spout_flowrate</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m^3/s</units>
</variable>
<variable>
<name>dyn.waterclock.intake_bucket_depth</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">5.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_overflow_height</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">4.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_clock_spout_height</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.25</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_water_level</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.total_ticks</name>
<tvInteger>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:int">60</value>
<unsigned>false</unsigned>
<format>Decimal</format>
</tvInteger>
<state>Valid</state>
<units>--</units>
</variable>
<variable>
<name>dyn.waterclock.current_tick</name>
<tvInteger>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:int">0</value>
<unsigned>false</unsigned>
<format>Decimal</format>
</tvInteger>
<state>Valid</state>
<units>--</units>
</variable>
<variable>
<name>dyn.waterclock.timer_bucket_depth</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">5.133689839572193</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.timer_water_level</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
</trickView>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<trickView>
<cyclePeriod>0.5</cyclePeriod>
<variable>
<name>dyn.waterclock.intake_overflow_flowrate</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m^3/s</units>
</variable>
<variable>
<name>dyn.waterclock.intake_clock_spout_flowrate</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m^3/s</units>
</variable>
<variable>
<name>dyn.waterclock.intake_bucket_depth</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">1.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_overflow_height</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.8</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_clock_spout_height</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.1</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_water_level</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.intake_bucket_vol</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m^3</units>
</variable>
<variable>
<name>dyn.waterclock.timer_bucket_depth</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">2.3077</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.timer_water_level</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.timer_bucket_vol</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m^3</units>
</variable>
<variable>
<name>dyn.waterclock.rf1.error</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>--</units>
</variable>
<variable>
<name>dyn.waterclock.rf2.error</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.0</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>--</units>
</variable>
<variable>
<name>dyn.waterclock.tick_gap</name>
<tvDouble>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:double">0.03846166666666666</value>
<format>Decimal</format>
</tvDouble>
<state>Valid</state>
<units>m</units>
</variable>
<variable>
<name>dyn.waterclock.total_ticks</name>
<tvInteger>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:int">60</value>
<unsigned>false</unsigned>
<format>Decimal</format>
</tvInteger>
<state>Valid</state>
<units>--</units>
</variable>
<variable>
<name>dyn.waterclock.current_tick</name>
<tvInteger>
<value xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:int">0</value>
<unsigned>false</unsigned>
<format>Decimal</format>
</tvInteger>
<state>Valid</state>
<units>--</units>
</variable>
</trickView>