/* From: "COMPUTATIONAL PHYSICS, 2nd Ed"
by RH Landau, MJ Paez, and CC Bordeianu
Copyright Wiley-VCH, 2007.
Electronic Materials copyright: R Landau, Oregon State Univ, 2007;
MJ Paez, Univ Antioquia, 2007; and CC Bordeianu, Univ Bucharest, 2007.
Support by National Science Foundation
*/
// HarmOscillatorIO.java: Sample of Javadoc and Java IO features
/* A note on documentation by Zlatko Dimcovic. Java comes with the tool 'javadoc,' that processes comments
* within a program that start with /** (2 asterisks). Within them one may use some HTML
* formatting (the first comment below does this, as an example). Run it on this file, as
* 'javadoc -d dirName file' (-d dirName is there only so that the files generated go into
* a separate directory). Then open the generated file HarmOscillator.html with a browser.
* This is how java documentation, including the official pages on sun's site, is made.
*/
import java.io.*;
import ptolemy.plot.*;
/**
* This is a simple demonstration of how one can parse command-line arguments,
* and of a few related chores:
*
–
* “try” for “exceptions” typical for this
* ({@code NumberFormatException}), and “catch” them
* (and do something simple)
*
–
* File names created with values of variables in them, and plots labeled
* and exported with these, during run-time
*
–
* Setting static (class variables) to command-line arguments; and a few other
* bits and pieces
*
(We also illustrate a few simple uses of the
* javadoc tool; the simple formatting
* above is for this purpose.)
* For information on java see, for example, Sun's java pages:
* JDK 5.0 Documentation,
* various tutorials
* (with a
* “Big
* Index”).
Also, becoming able to use, and getting used to,
* API Specification
* – for any language – is usually a very good idea.
*/
public class HarmOscillatorIO {
static final double PI = Math.PI; // A constant: "final" cannot be changed.
// Parameters used throughout; defaults:
static int N = 100; // number of iterations (sampling points)
static double w = 1.0; // frequency
static double dC = 0.1; // damping coefficient
static double amp = 5.0; // amplitude
public static void main(String[] args) throws IOException, FileNotFoundException
{
String filename = "oscillator"; // Base for names (formed below):
String exportPlotTo = "oscPlotExport"; // for data and exported plot.
/* Note the use of "scoping" below: we may use exact same variable names as we
* have defined above, since N,w,amp below are local in scope to the block in
* which they are declared; and they "shadow" those set above, within this block.
* (Variables exist only within the innermost block of code they are declared in.)
* This is mostly for demonstration though; be careful with it, errors do arise.
*/
if ( args.length == 3 || args.length == 4 )
{
int N = 0; // Can't declare inside the "try" block: it wouldn't exist outside!
try { // Use "exceptions": java "throws"
N = Integer.parseInt( args[0] ); // them, when wrong things happen
} // (eg: text read into a number),
catch (NumberFormatException nfe) { // but one has to "try" and "catch"
System.err.println("The first argument has to be an integer.");
System.exit(1);
}
// For brevity, we don't check now -- try running the program with bad arguments.
double w = Double.parseDouble( args[1] ), // Declare these new variables only
dC = Double.parseDouble( args[2] ); // for convenience, for passing to:
params( N, w, dC ); // this method sets static's
filename = filename + "_N" + N + "_w" + w + ".dat";
exportPlotTo += "_N" + N + "_w" + w + ".eps"; // append to basenames
if ( args.length == 4 ) // enter filename on cmdline?
filename = args[3];
}
else { // exit with a message; print to System.err, so it is not redirected
System.err.println(
"\n\tUsage: java harmOscillator numIterations freq dampCoeff [filename.dat]\n");
System.err.println(
"\t( A reasonable invokation: java HarmOscillator 100 5 0.2 )\n");
System.exit(1); // note: "\n" not portable
}
PrintWriter fw = new PrintWriter( new FileWriter(filename), true );
Plot pt = new Plot();
double a = 0, b = 10, h = (b-a)/N; // limits; step size
double t = a; double x1 = amp; double x2 = amp;
/* 'do-while' loop: normally used to make sure code in the body executes at least
* once, before the while test. ('while' loop may never execute, if the condition
* fails to start with.) Here we simply want to have t=0 point too, before +=h.
*/
do {
x1 = f1(t);
x2 = f2(t);
pt.addPoint(0, t, x1, true);
pt.addPoint(1, t, x2, true);
fw.println(t + " " + x1 + " " + x2);
}
while ( (t += h) < b ); // increment t by h, then test this against b
pt.setXLabel("time"); pt.setYLabel("damped sin; sin");
pt.setMarksStyle("dots", 0); pt.setMarksStyle("points", 1);
pt.addLegend(0, "exp(-g*t)*sin(t)"); pt.addLegend(1, "sin(t)");
// Prepare title; show only one decimal place (correctly rounded)
String ptTitle = roundToDecPlaces(w*N*h/(2*PI), 1) + " cycles; freq = "
+ roundToDecPlaces(w, 2) + ", damp: g=" + dC + " (step : " + h + ")";
pt.setTitle( ptTitle );
PlotApplication showPt = new PlotApplication(pt); // now draw plot on screen
pt.export( new FileOutputStream(exportPlotTo) ); // export plot (to eps format)
} // end of main
/** Set class variables: number of iterations, frequency, damping coefficient. */
public static void params (int noCyc, double freq, double dampCoeff)
{
N = noCyc; w = freq; dC = dampCoeff;
}
/** Set class variables, overloaded: also set amplitude. */
public static void params (int noCyc, double freq, double dampCoeff,
double amplitude)
{
N = noCyc; w = freq; dC = dampCoeff; amp = amplitude;
}
/** Round {@code numToRound} to the {@code precision} number of decimal places.
* It makes use of the
*
* java.Math.round(double) method.
* @see
* java.text.DecimalFormat.format(double)
* @see
* java.util.Formatter
* @see
* java.text.*
* @see
* String.format(...)
* @see
* java.math.BigDecimal
*/
/*
* There are more systemic ways; for example, one would be to use formatting from
* java.text.DecimalFormat class (java.text.DecimalFormat then has to be import-ed):
* DecimalFormat df = new DecimalFormat("#0.0"); df.format(w); -- and then whenever
* you want such format to be applied you use df.format(var); this returns a string,
* and it is meant for displaying values conveniently. One can also do it in one go:
* (new DecimalFormat("#0.0")).format(w). Or we can use casting, with a possible slight
* loss of precision: ((int) (10*w))/10.0. Also, one can use C-style formatting with
* System.out.printf(...). And then there is a number of yet other ways; see links.
*
* Note that our method rounds to a (decimal representation of) an int when invoked
* with precision<=0, while it should really raise an error/exception.
*/
public static double roundToDecPlaces(double numToRound, int precision)
{
double factor = 1.;
for (int i = 0; i < precision; i++)
factor *= 10.0 ; // or use factor=Math.pow(10.0, precision)
return ( precision > 0 )
? (Math.round( factor * numToRound )) / factor
: Math.round( numToRound ); // for prec<=0 should really report error
}
/** Computes position for a given time for a damped harmonic oscillator.
* (It should check for errors during the computation, and throw exceptions
* or return small integer indicating success/failure; but it does not.)
* @param t time at which to calculate position
* @return the position at this time.
*/
public static double f1(double t)
{
return amp * Math.exp(-dC*t) * Math.sin(w*t);
}
/** Computes position for a given time for a harmonic oscillator. */
public static double f2(double t)
{
return amp * Math.sin(w*t);
}
}