import java.applet.*; import java.awt.*; import java.io.*; import java.lang.Math; // $Id: WaterProperties.java,v 1.26 1997/07/03 20:54:30 kelley Exp $ // Based on p619 /** This class computes properties of water (and seawater), using the UNESCO equation of state (ref: Gill, A. E., 1982. Atmosphere-ocean dynamics. Academic Press, New York) @author Dan E. Kelley @version 1.4 */ public class WaterProperties extends Applet { TextField S_Field; TextField T_Field; TextField p_Field; Label theta_Field; Label density_Field; Label sigmat_Field; Label sigmatheta_Field; Label alpha_Field; Label beta_Field; Label compressibility_Field; Label Tfreeze_Field; Label Cp_Field; Button recalc; String msg_theta = "Potential temperature = 9.988 degC "; String msg_density = "In-situ density = 1027.4044 kg/m^3 "; String msg_sigmat = "Sigma-t = 1026.9524 kg/m^3 "; String msg_sigmatheta = "Sigma-theta = 1026.9544 kg/m^3 "; String msg_alpha = "alpha = 1.686e-4 1/degC "; String msg_beta = "beta = 7.596e-4 1/PSU "; String msg_compressibility = "compressibility = 4.395e-6 1/dbar "; String msg_Tfreeze = "Freezing temperature = -2.00 degC "; String msg_Cp = "Specific heat = 3983.62 J/kg/degC "; /** density(S,T,p) -- computes in-situ density @param S Salinity in PSU @param T In-situ temperature in degC @param p Pressure, in decibar (nominally, 1dbar = 1m of water) */ public double density(double S, double T, double p) { // from EOS double rho_w, Kw, Aw, Bw, p1, S12, ro, xkst; rho_w = 999.842594 + T * (6.793952e-2 + T * (-9.095290e-3 + T * (1.001685e-4 + T * (-1.120083e-6 + T * 6.536332e-9)))); Kw = 19652.21 + T * (148.4206 + T * (-2.327105 + T * (1.360477e-2 - T * 5.155288e-5))); Aw = 3.239908 + T * (1.43713e-3 + T * (1.16092e-4 - T * 5.77905e-7)); Bw = 8.50935e-5 + T * (-6.12293e-6 + T * 5.2787e-8); p1 = 0.1 * p; S12 = Math.sqrt(S); ro = rho_w + S * (8.24493e-1 + T * (-4.0899e-3 + T * (7.6438e-5 + T * (-8.2467e-7 + T * 5.3875e-9))) + S12 * (-5.72466e-3 + T * (1.0227e-4 - T * 1.6546e-6) + S12 * 4.8314e-4)); xkst = Kw + S * (54.6746 + T * (-0.603459 + T * (1.09987e-2 - T * 6.1670e-5)) + S12 * (7.944e-2 + T * (1.6483e-2 + T * (-5.3009e-4)))) + p1 * (Aw + S * (2.2838e-3 + T * (-1.0981e-5 + T * (-1.6078e-6)) + S12 * (1.91075e-4)) + p1 * (Bw + S * (-9.9348e-7 + T * (2.0816e-8 + T * (9.1697e-10))))); return (ro / (1.0 - p1 / xkst)); } /** theta(S,T,p) -- computes potential temperature @param S Salinity in PSU @param T In-situ temperature in degC @param p Pressure, in decibar (nominally, 1dbar = 1m of water) */ public double theta(double S, double T, double p) { S -= 35.00; p /= 10.0; // formula is in bars!! return (double) T - p * (((3.6504e-4 + T * (8.3198e-5 + T * (-5.4065e-7 + T * 4.0274e-9))) + S * (1.7439e-5 - T * 2.9778e-7)) + p * ((8.9309e-7 + T * (-3.1628e-8 + T * 2.1987e-10) - S * 4.1057e-9) + p * (-1.6056e-10 + T * 5.0484e-12))); } /** sigmat(S,T,p) @param S Salinity in PSU @param T In-situ temperature in degC @param p Pressure, in decibar (nominally, 1dbar = 1m of water) */ public double sigmat(double S, double T, double p) { return density(S, T, 0); } /** sigmatheta(S,T,p) @param S Salinity in PSU @param T In-situ temperature in degC @param p Pressure, in decibar (nominally, 1dbar = 1m of water) */ public double sigmatheta(double S, double T, double p) { return density(S, theta(S, T, p), 0); } public double alpha(double S, double T, double p) { double rhoMinus = density(S, T - 1.0e-5, p); double rhoPlus = density(S, T + 1.0e-5, p); return (rhoMinus - rhoPlus) / (rhoMinus + rhoPlus) / 1.0e-5; } public double beta(double S, double T, double p) { if (S == 0) S += 1.5e-5; // prevent sqrt(negative) double rhoMinus = density(S - 1.0e-5, T, p); double rhoPlus = density(S + 1.0e-5, T, p); return (rhoPlus - rhoMinus) / (rhoMinus + rhoPlus) / 1.0e-5; } public double compressibility(double S, double T, double p) { // ERROR: should be using constant-theta not constant-T double dp = 0.1; double rhoMinus = density(S, T, p - dp); double rhoPlus = density(S, T, p + dp); return (rhoPlus - rhoMinus) / (rhoMinus + rhoPlus) / dp; } /** freezing_temperature(S, p) REFERENCE A.E. Gill, 1982. "Atmosphere-Ocean Dynamics". Academic Press. (Section A3.7, page 602). Or see UNESCO technical papers in marine science, */ public double Tfreeze(double S, double p) { return ( -0.0575 * S + 1.710523e-3 * S * Math.sqrt(S) - 2.154996e-4 * S * S - 7.53e-4 * p); } public double Cp_OLD(double S, double T, double p) { //System.out.println("S=" + S); //System.out.println("T=" + T); double Cp0 = 4217.4 + T * (-3.720283 + T * (0.1412855 + T * (-2.654387e-3 + T * (2.093236e-5)))); //System.out.println("Cp0=" + Cp0); double rval = Cp0 + S * (-7.6444 + T * (0.107276 + T * (-1.3839e-3))) + S * Math.sqrt(S) * (0.17709 + T * (-4.0772e-3 + T * (5.3539e-5))); //System.out.println("Cp=" + rval); return rval; } public double Cp(double S, double T, double p) { /** specific heat at constant pressure based on Millero et. al. jgr 78:4499-4507 (1973) and Fofonoff(1985) correction made to coefficients a b and c S salinity T temperature p pressure (dbars) Cp specific heat (j kg-1 k-1) Test value: Cp(40.,40.,1000.)=3963.137778427 dave hebert 03/05/86 */ double pr=0.1*p; double a=4217.4+T*(-3.720283+T*(0.1412855+T*(-2.654387e-3+T*2.093236e-5))); double b=-7.644405+T*(0.1072763-T*1.38385e-3); double c=0.1770898+T*(-4.07718e-3+T*5.354e-5); double d=-0.49592+T*(1.45747e-2+T*(-3.13885e-4+T*(2.0357e-6+T*1.7168e-8))); double e=4.9247e-3+T*(-1.28315e-4+T*(9.802e-7+T*(2.5941e-8-T*2.9179e-10))); double f=-1.2331e-4+T*(-1.517e-6+T*3.122e-8); double g=2.4931e-4+T*(-1.08645e-5+T*(2.87533e-7+T*(-4.0027e-9+T*2.2956e-11))); double h=-2.9558e-6+T*(1.17054e-7+T*(-2.3905e-9+T*1.8448e-11)); double h1=-5.422e-8+T*(2.6380e-9+T*(-6.5637e-11+T*6.136e-13)); double h2=5.540e-10+T*(-1.7682e-11+T*3.513e-13); double S1=S * Math.sqrt(S); double Cp=a+b*S+c*S1+pr*(d+e*S+f*S1+pr*(g+h*S+9.971e-8*S1+pr*(h1+h2*S-1.4300e-12*S1))); return Cp; } public void init() { GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setLayout(gridbag); Label S_label = new Label("Salinity (PSU)", Label.LEFT); Label T_label = new Label("Temperature (degC)", Label.LEFT); Label p_label = new Label("Pressure (dbar)", Label.LEFT); S_Field = new TextField("35.000", 10); T_Field = new TextField("10.000", 10); p_Field = new TextField("100.00", 10); theta_Field = new Label(msg_theta, Label.CENTER); density_Field = new Label(msg_density, Label.CENTER); sigmat_Field = new Label(msg_sigmat, Label.CENTER); sigmatheta_Field = new Label(msg_sigmatheta, Label.CENTER); alpha_Field = new Label(msg_alpha, Label.CENTER); beta_Field = new Label(msg_beta, Label.CENTER); compressibility_Field = new Label(msg_compressibility, Label.CENTER); Tfreeze_Field = new Label(msg_Tfreeze, Label.CENTER); Cp_Field = new Label(msg_Cp, Label.CENTER); recalc = new Button("Calculate"); c.weightx = 1.0; c.gridwidth = GridBagConstraints.RELATIVE; gridbag.setConstraints(S_label, c); add(S_label); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(S_Field, c); add(S_Field); c.gridwidth = GridBagConstraints.RELATIVE; gridbag.setConstraints(T_label, c); add(T_label); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(T_Field, c); add(T_Field); c.gridwidth = GridBagConstraints.RELATIVE; gridbag.setConstraints(p_label, c); add(p_label); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(p_Field, c); add(p_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(recalc, c); add(recalc); c.weightx = 1.0; c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(theta_Field, c); add(theta_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(density_Field, c); add(density_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(sigmat_Field, c); add(sigmat_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(sigmatheta_Field, c); add(sigmatheta_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(alpha_Field, c); add(alpha_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(beta_Field, c); add(beta_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(compressibility_Field, c); add(compressibility_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(Tfreeze_Field, c); add(Tfreeze_Field); c.gridwidth = GridBagConstraints.REMAINDER; gridbag.setConstraints(Cp_Field, c); add(Cp_Field); } public void recalculate() { try { Double SS = new Double(S_Field.getText());// p361 double S = SS.doubleValue(); Double TT = new Double(T_Field.getText());// p361 double T = TT.doubleValue(); Double pp = new Double(p_Field.getText());// p361 double p = pp.doubleValue(); double tmp; tmp = density(S, T, p); density_Field.setText("In-situ density = " + tmp + " kg/m^3"); tmp = theta(S, T, p); theta_Field.setText("Potential temperature = " + tmp + " degC"); tmp = sigmat(S, T, p); sigmat_Field.setText("Sigma-t = " + tmp + " kg/m^3"); tmp = sigmatheta(S, T, p); sigmatheta_Field.setText("Sigma-theta = " + tmp + " kg/m^3"); tmp = alpha(S, T, p); alpha_Field.setText("alpha = " + tmp + " 1/degC"); tmp = beta(S, T, p); beta_Field.setText("beta = " + tmp + " 1/PSU"); tmp = compressibility(S, T, p); compressibility_Field.setText("compressibility = " + tmp + " 1/dbar"); Tfreeze_Field.setText("Freezing temperature = " + Math.floor(0.5+1000*Tfreeze(S,p))/1000.0 + " degC"); tmp = Cp(S, T, p); Cp_Field.setText("Specific heat = " + tmp + " J/kg/degC"); } catch (NumberFormatException e) { density_Field.setText("Density = ????.???? kg/m^3"); theta_Field.setText("Potential temperature = ??.???? degC"); sigmat_Field.setText("Sigma-t = ????.???? kg/m^3"); sigmatheta_Field.setText("Sigma-theta = ????.???? kg/m^3"); alpha_Field.setText("alpha = ?.???e?? 1/degC"); beta_Field.setText("beta = ?.???e?? 1/psu"); compressibility_Field.setText("compressibility = ?.???e-6 1/dbar "); Tfreeze_Field.setText("Freezing temperature = ??.???? degC"); Cp_Field.setText("Specific heat = ????.?? J/kg/degC"); } } public boolean action(Event evtObj, Object arg) { if (evtObj.target instanceof TextField) { // System.out.println("got a hit on a TextField " + arg); recalculate(); repaint(); return true; } else if (evtObj.target instanceof Button) { if (arg.equals("Calculate")) { recalculate(); repaint(); return true; } } return false; } public void paint(Graphics g) { } }