/**************************************************************************
 ******** File:        SpeedOfSound.java                           ********
 ******** Description: A program for computing speed of sound      ********
 ******** Project:     ACMUS                                       ********
 ********              A system for the design and simulation of   ********
 ********              musical listening environments acoustics    ********
 ******** Author:      Yang Yili (yili@linux.ime.usp.br)           ********
 ******** Institution: Department of Computer Science              ********
 ********              Institute of Mathematics and Statistics     ********
 ********              University of São Paulo                     ********    
 **************************************************************************/
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.lang.*;
/**
 * Computes speed of sound
 * @author Yang Yili
 */
public class SpeedOfSound extends Applet
{ 
    private void add(Component c, GridBagLayout gbl, 
		     GridBagConstraints gbc,
		     int x, int y, int w, int h)
    {
	gbc.gridx = x;
	gbc.gridy = y;
	gbc.gridwidth = w;
	gbc.gridheight = h;
	gbl.setConstraints(c, gbc);
	add(c);
    }
     /**
     * Applet initialization
     * @param no parameter 
     */
    public void init()
    {   
        setBackground(Color.gray);		
	GridBagLayout  gbl = new GridBagLayout();
	setLayout(gbl);
	GridBagConstraints gbc = new GridBagConstraints();
	gbc.fill = GridBagConstraints.BOTH;
	gbc.weightx = 0;
	gbc.weighty = 0;
	Label label = new Label("Relative humidity (0-100%)");
	add(label, gbl, gbc, 0, 0, 2, 1);
	humidity = new TextField("0", 3);
	add(humidity, gbl, gbc, 2, 0, 1, 1);
	label = new Label("Temperature (0-30 C)");
	add(label, gbl, gbc, 3, 0, 2, 1);
	temperature = new TextField("0", 3);
	add(temperature, gbl, gbc, 5, 0, 1, 1);
	Button button = new Button("Compute");
	button.addActionListener(new Button1());
	add(button, gbl, gbc, 0, 2, 1, 1);
	label = new Label("Speed of Sound (m/s)");
	add(label, gbl, gbc, 3, 2, 2, 1);
	speed = new TextField("331.4 ", 10);
	add(speed, gbl, gbc, 5, 2, 2, 1);
    }/* method init */

    /** 
     * Describes the action to be performed when a user 
     * clicks the button "Compute"
     * @author Yang Yili
     */
    class Button1 implements ActionListener
    {
	/** 
	 * Describes the action to be performed when a user 
	 * clicks the button "Compute"
	 * @param e ActionEvent
	 */
	public void actionPerformed(ActionEvent e)
	{
	    String s1 = temperature.getText();	
	    Double d1 = Double.valueOf(s1);
	    double x = Math.abs(d1.doubleValue());
	    String s2 = humidity.getText();
	    Double d2 = Double.valueOf(s2);
	    double y = Math.abs(d2.doubleValue());
	    if (inputValid(x,y) == true) 
	    {
	        CalculateSpeedOfSound cal = new CalculateSpeedOfSound(x, y);
	        double velocity = cal.calculateSpeedOfSound();
		velocity = velocity * 10;
		int aux = (int) velocity;
		velocity = (double) aux / 10;
	        speed.setText("" + velocity);
	    }
	    else
		speed.setText("Invalid Input");
	}/* method actionPerformed */

    }/* class Button1 */

    /**
     * Verifies the input validity
     * @param x temperature
     * @param y humidity
     * @return true if temperature and humidity are within
     * acceptable ranges and false otherwise
     */
    boolean inputValid(double x, double y)
    {
	if((x >= 0.0 && x <= 30.0) && (y >= 0.0 && y <= 100.0))
	    return true;
	else
	    return false;
    }
    private TextField temperature;
    private TextField humidity;
    private TextField speed;
}
 
/**
 * Computes speed of sound
 * @author Yang Yili
 */
class CalculateSpeedOfSound
{
    /**
     * Creates a new CalculateSpeedOfSound
     * @param x temperature
     * @param y humidity
     */
    public CalculateSpeedOfSound(double x, double y)
    {
	temp = x;
	humidity = y;
    }
    /**
     * Computes speed of sound
     * @param no parameter
     * @return speed speed of sound
     */
    public double calculateSpeedOfSound()
    {
	a[0] = 331.5024;
	a[1] = 0.603055;
	a[2] = -0.000528;
	a[3] = 51.471935;
	a[4] = 0.1495874;
	a[5] = -0.000782;
	a[6] = -1.82e-7;       
	a[7] = 3.73e-8;         
	a[8] = -2.93e-10;     
	a[9] = -85.20931;
	a[10] = -0.228525;
	a[11] = 5.91e-5;  
	a[12] = -2.835149;
	a[13] = -2.15e-13; 
	a[14] = 29.179762;
	a[15] = 0.000486;
	T = temp + 273.15;
	h = humidity /100.0;
	f = 1.00062 + 0.0000000314 * p + 0.00000056 * temp * temp;
	Psv = Math.exp(0.000012811805 * T * T - 0.019509874 * T + 
		       34.04926034 - 6353.6311 / T);
	Xw = h * f * Psv / p;
	c = 331.45 - a[0] - p * a[6] - a[13] * p * p;
	c = Math.sqrt(a[9] * a[9] + 4 * a[14] * c);
	Xc = ((-1) * a[9] - c) / ( 2 * a[14]);
	speed = a[0] + a[1] * temp + a[2] * temp * temp + 
	        (a[3] + a[4] * temp + a[5] * temp * temp) * Xw + 
                (a[6] + a[7] * temp + a[8] * temp * temp) * p + 
                (a[9] + a[10] * temp + a[11] * temp * temp) * Xc + 
                a[12] * Xw * Xw + a[13] * p * p + a[14] * Xc * Xc + 
                a[15] * Xw * p * Xc;
	return (speed);
    }/* method calculateSpeedOfSound */

	private final double p = 101000;
	private double[] a = new double[16];
	private double temp;
	private double humidity;
	private double T;
	private double f, h, Psv, Xw, Xc;
	private double c;
	private double speed;
}/* class CalculateSpeedOfSound */





