Home | | Mathematics | | * Applied Mathematics | | * Storage Tank Modeling | | Share This Page |
A special-case analyzer for large storage tanks.
Copyright © 2009, Paul Lutus — Message Page
/*************************************************************************** * Copyright (C) 2009 by Paul Lutus * * [email protected] * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ import java.util.*; import java.io.*; /** * * @author lutusp.arachnoid.com */ final public class TankStepped { final public String VERSION = "1.1"; final int fieldWidth = 18; final int decimalPlaces = 3; final String nFormat = "%" + fieldWidth + "." + decimalPlaces + "f"; final String csvFormat = "%." + decimalPlaces + "f"; final String sFormat = "%" + fieldWidth + "s"; final int BOTTOMSECTION = 0; final int MIDDLESECTION = 1; final int TOPSECTION = 2; boolean csvMode = false; String name; class TankSection { double r; double h; public TankSection(double r, double h) { this.r = r; this.h = h; } }; Vector<TankSection> sections; public TankStepped() { name = getClass().getName(); } /* * The tank being modeled has an inverted cone at the bottom, * some stepped-radius cylinders in the middle section, * and a spherical-segment top. */ double computeSectionPartialVolume( int section, double r, double h, double y) { double v = 0; double q; final double pid6 = Math.PI / 6.0; switch (section) { case BOTTOMSECTION: // inverted cone if (h != 0) { q = r * (y / h); v = Math.PI * q * q * y / 3.0; } break; case MIDDLESECTION: // all middle sections are cylinders v = Math.PI * r * r * y; break; case TOPSECTION: // spherical segment double mr = (r * r + h * h) / (2 * h); // compute a segment of a sphere // between y and h double hh = (h - y); double qr = mr - hh; double rr = Math.sqrt(mr * mr - qr * qr); // the full segment volume v = (3 * r * r + h * h) * h; // subtract the section above y v -= (3 * rr * rr + hh * hh) * hh; // multiply by constant v *= pid6; break; } return v; } String formatRecord(String format, double a, double b) { if (csvMode) { return String.format(csvFormat + "," + csvFormat, a, b); } else { return String.format(nFormat + " " + nFormat, a, b); } } String formatRecord(String format, String a, String b) { if (csvMode) { return String.format("%s,%s", a, b); } else { return String.format(sFormat + " " + sFormat, a, b); } } /** * @param by y bisector within tank height * @param nFormat numeric format for table record * @returns table record as string */ String computeTankPartialVolume(double by, String nFormat) { double volume = 0; double y = by; Iterator<TankSection> it = sections.iterator(); // step throught tank sections, // add full volumes of all sections // less than y, then add partial volume // for section bisected by y while (y > 0 && it.hasNext()) { TankSection s = it.next(); // section = (first element = 0), (between = 1), (last element = 2) int tSec = (s == sections.firstElement()) ? BOTTOMSECTION : (s == sections.lastElement()) ? TOPSECTION : MIDDLESECTION; if (s.h >= y) { // y lies within this section's height, // so add partial volume for this section volume += computeSectionPartialVolume(tSec, s.r, s.h, y); // and set y to zero so loop exits y = 0; } else { // y is greater than present section height, // so add full volume for this section volume += computeSectionPartialVolume(tSec, s.r, s.h, s.h); // and subtract this section's height from y y -= s.h; } } return formatRecord(nFormat, by, volume); } /** * @param n table step size if < 0 or arg if > 0 * @param height tank overall height */ void createTable(double n, double height) { double y = 0, ty; double pv; Vector<String> vs = new Vector<String>(); String fs = formatRecord(sFormat, "Height", "Volume"); vs.add(fs); if (n < 0) { // user has entered a table step size for (int iy = 0; (ty = iy * -n) <= height; iy++) { y = ty; fs = computeTankPartialVolume(y, nFormat); //fs = String.format(nFormat,y,pv); vs.add(fs); } // compute one more value to deal with rounding issues String ns = computeTankPartialVolume(height, nFormat); // if this isn't identical to the prior entry if (!ns.equals(fs)) { vs.add(ns); } } else { // user has entered a single argument n = (n > height)?height:n; fs = computeTankPartialVolume(n, nFormat); vs.add(fs); } // now print the table Iterator<String> is = vs.iterator(); while (is.hasNext()) { System.out.println(is.next()); } } /** * @param args copy of command line arguments */ void process(String[] args) { int i = 0; if (args.length > 0 && args[0].equals("-v")) { System.out.println(name + " version " + VERSION); } else { if (args.length < 7) { System.out.println("usage: [-v version] [-c (csv mode)] (tank section radius/height pairs) r h r h r h ... (-n = table stepsize or +n = arg) n"); System.out.println(" see http://arachnoid.com/TankCalc/TankStepped.html for more instructions."); } else { try { if (args[0].equals("-c")) { csvMode = true; i++; } double height = 0; sections = new Vector<TankSection>(); int top = args.length; for (; i < top - 1; i += 2) { double r = Double.parseDouble(args[i]); double h = Double.parseDouble(args[i + 1]); sections.add(new TankSection(r, h)); height += h; } // if required, convert major radius entry // to minor radius for spherical top cap TankSection s = sections.lastElement(); if (s.h > s.r) { height -= s.h; s.h = s.h - Math.sqrt(s.h * s.h - s.r * s.r); height += s.h; } if (i < args.length) { double step = Double.parseDouble(args[i]); createTable(step, height); } else { throw new Exception("No stepsize or argument entry."); } } catch (Exception e) { System.out.println(name + ": Error: " + e); } } } } /** * @param args the command line arguments */ public static void main(String[] args) { TankStepped ts = new TankStepped(); ts.process(args); } }
Home | | Mathematics | | * Applied Mathematics | | * Storage Tank Modeling | | Share This Page |