//*********************************************************************************
// class TestVSOP87 // default package
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
import jephem.astro.planets.vsop87.VSOP87;
import jephem.astro.Body;
import jephem.astro.SolarSystemConstants;
import jephem.util.JEphemException;
import jephem.astro.AstroException;
import java.io.*;
import java.util.Date;
import java.text.NumberFormat;
/******************************************************************
Contains methods used to test package <CODE>jephem.astro.planets.vsop87</CODE>.
<BR>JEphem program doesn't use it ; it was used to build JEphem.
<BR>This class is dependant from <CODE>jephem</CODE> package, which must be in the classpath.
<BR>In this class, when arrays characterizing planetary data were needed (ex : for "planetNames"), the indexes of <CODE>jephem.astro.SolarSystemConstants.java</CODE> were used.
@author Thierry Graff
@history jan 20 2001 creation.
@history dec 18 2001 review, cleaned the comments.
@todo modify formulae in calcGeocentricError() (take eccentricity into account)
*****************************************************************/
public abstract class TestVSOP87 implements SolarSystemConstants{
//=================================================================================
// CONSTANTS
//=================================================================================
/** Filter applied to BDL series (full precision or truncated). */
private static int testedFilter;
/** Type of output. String of 2 characters ; each character indicates if the corresponding type
of output is desired. See parameter 'OutputType' of testJEphemPrecision. */
private static String strOutputType;
/** Number of JDs concerned by the test. */
private static int _nbJD;
/** Number of planets concerned by the test. */
private static int _nbPlan;
private static final int NB_COORD = 6;
/** Values of the tests computed by BDL. */
private static JEphemTest[][] bdlT;
/** Values of the tests computed by JEphem. */
private static JEphemTest[][] jephemT;
/** Differences between the values of JEphem and BDL [planet][jd][coord]. */
private static double[][][] delta;
/** Norms of vectors representing the difference of position [planet][jd]. */
private static double[][] deltaNormPos;
/** Norms of vectors representing the difference of velocity [planet][jd]. */
private static double[][] deltaNormVel;
/** Maximal norms of vectors representing the difference of position [planet]. */
private static double[] deltaMaxNormPos;
/** Maximal norms of vectors representing the difference of velocity [planet]. */
private static double[] deltaMaxNormVel;
/** To know computation time. */
private static Date startCalcTime, endCalcTime;
//=================================================================================
// CONSTANTS
//=================================================================================
// planet names ; indexes correspond to jephem.astro.ISolarSystem.java constants.
private static String[] planetNames = {"", "", "Mercury", "Venus", "Earth", "Mars", "Jupiter",
"Saturn", "Uranus", "Neptune"};
// semi-major axis ; index corresopnd to jephem.astro.ISolarSystem.java constants.
private final static double[] a0s = {0.0, 0.0, 0.39, 0.72, 1.00, 1.52, 5.20, 9.55, 19.22, 30.11}; // au
// eccentricities ; index corresopnd to jephem.astro.ISolarSystem.java constants.
private static double[] eccs = {0.0, 0.0, 0.21, 0.01, 0.02, 0.09, 0.05, 0.06, 0.05, 0.01};
private static final String[] strUnitPos = {"au", "au", "au", "au/d", "au/d", "au/d"};
private static final String[] coordNames = {"x", "y", "z", "x'", "y'", "z'"};
// Repeats fields of JEphem
private static final int FILTER_FULL = 0;
private static final int FILTER_JEPHEM = 1;
private static final int FILTER_BDL = 2;
// Absolute path to the files containing terms for summation (for full prec. only)
private final static String DATA_PATH = "d:\\b_dvpt\\jephem\\data\\astro\\planets\\vsop87\\VSOP87A\\";
private static final String LS = System.getProperty("line.separator");
private static final NumberFormat NF = NumberFormat.getNumberInstance();
private static final NumberFormat NF2 = NumberFormat.getNumberInstance();
static{
NF.setMaximumFractionDigits(10);
NF.setMinimumFractionDigits(10);
NF2.setMaximumFractionDigits(3);
NF2.setMinimumFractionDigits(3);
};
//=================================================================================
// PUBLIC METHODS
//=================================================================================
//****************** main() ************************
/** Entry point to call the different methods of the class.
<BR>If the first element of <CODE>args</CODE> is "testPerf", <CODE>testPerf()</CODE> is called.
<BR>Otherwise, <CODE>testJEphemPrecision()</CODE> is called.
*/
public static void main(String[] args){
// for (int i = 0; i < args.length; i++) System.out.println(args[i]);
if(args[0].equalsIgnoreCase("testPerf")){
testPerf(args[1], args[2], args[3]);
}
else
testJEphemPrecision(args[0], args[1], args[2], args[3], args[4], args[5]);
}// end main
//**************** testJEphemPrecision() ****************************************
/** Method used to test results from JEphem compared with BDL text files.
<LI>To work, the check file must be in the current directory.</LI>
<LI>This method assumes that the corresponding version is used by JEphem.</LI>
<LI>To make it run, jephem package must be in the classpath (a simple way is to use the
'classpath' option from the 'java' tool).</LI>
<LI>To work properly, all the tested planets must be computable by JEphem (for example,
'EARTH-MOON' was removed from the file to test VSOP87A).</LI>
<BR><BR>It parses the .chk file, calls JEphem to compute the corresponding results (for all
JDs and planets), put all these data in arrays.
<B>Output</B> : a serie of tables, HTML formatted, permitting to compare the results of JEphem
with tests provided by the BDL. Result can be seen on JEphemSite.
<BR><BR>Example of call : <CODE>TestVSOP87 vsop87A.chk 10 8 FULL DETAIL,DIFF,SUMMARY test_jephem_full.htm</CODE>
@param checkFile : Name of a file containing extracts from ftp://ftp.bdl.fr/pub/planets/... VSOP87.chk,
containing only the tests for the concerned version.
<BR>'checkFile' name is assumed to start with "VSOP87X", where X represents the Version letter.
@param strNbJD Number of julian days concerned with the tests.
@param strNbPlan Number of planets concerned with the tests.
@param strFilter Part of JEphem to test (full precision, truncated). Can take the values "JEPHEM"
or "BDL" or "FULL".
@param outputType Output to generate : can be :
<LI>"DETAIL" : comparison of each value of the tests with the values computed by JEphem, ordered
by julian day ;</LI>
<LI>"DIFF" : differences between BDL results and JEphem, ordered by planet.</LI>
<LI>"SUMMARY" A summary table containing only the maximal geocentric errors.</LI>
To get more than one of these outputs, write the different values separated with comas, without
space (ex : "DETAIL,DIFF").
@param outputFile Name of the file to be generated (HTML format).
@history jan 20 2001 : creation.
@history aug 15 2001 : adaptation to new version of VSOP87.java.
@better a matching could be done with planetNames
********************************************************************************/
public static void testJEphemPrecision(String checkFile, String strJD, String strNbPlan,
String strFilter, String outputType, String outputFile){
// *** 1 - Parameter parsing
// _nbJD
_nbJD = Integer.parseInt(strJD);
System.out.println("_nbJD = " + _nbJD);
// _nbPlan
_nbPlan = Integer.parseInt(strNbPlan);
System.out.println("_nbPlan = " + _nbPlan);
// tested filter
if (strFilter.indexOf("FULL") != -1){
testedFilter = FILTER_FULL;
}
else if (strFilter.indexOf("BDL") != -1){
testedFilter = FILTER_BDL;
}
else if (strFilter.indexOf("JEPHEM") != -1){
testedFilter = FILTER_JEPHEM;
}
else {
System.out.println("'strFilter' parameter not correct");
return;
}
System.out.println("strFilter = " + strFilter);
//output type
strOutputType = "";
if (outputType.indexOf("DETAIL") != -1) strOutputType += "1";
else strOutputType += "0";
if (outputType.indexOf("DIFF") != -1) strOutputType += "1";
else strOutputType += "0";
if (outputType.indexOf("SUMMARY") != -1) strOutputType += "1";
else strOutputType += "0";
if (outputType.equals("000")){
System.out.println("No correct output found - check 'ouputType' parameter");
return;
}
System.out.println("strOutputType = " + strOutputType);
// *** 2 - get the data
System.out.println("Getting BDL results...");
getBDLResults(checkFile);
System.out.println("Getting JEphem results...");
getJEphemResults();
System.out.println("Computing the differences...");
getDifferences();
// *** 3 - compute the output
System.out.println("Generating the output...");
try{
FileOutputStream fos = new FileOutputStream(new File(outputFile));
String strRes = buildOutputBeginning();
fos.write(strRes.getBytes());
if (strOutputType.charAt(2) == '1')
buildOutputSummary(fos);
if (strOutputType.charAt(1) == '1')
buildOutputDiffByPlanet(fos);
if (strOutputType.charAt(0) == '1')
buildOutputDetailByJD(fos);
//End
strRes = "</BODY></HTML>";
fos.write(strRes.getBytes());
fos.close();
}
catch(Exception e){
e.printStackTrace();
System.exit(0);
}
}// end testJEphemPrecision
//**************************** testPerf() **************
/** Calls <CODE>jephem.astro.planets.vsop87.VSOP87</CODE> several times and displays the time taken by the
computations.
*/
//2451545.0 = 1/1/2000
public static void testPerf(String strNbDates, String strBaseJD,
String strPrecision){
try{
// parameter parsing
int nbDates = Integer.parseInt(strNbDates);
double baseJD = Double.parseDouble(strBaseJD);
double precision = Double.parseDouble(strPrecision);
System.out.println(nbDates + " computations");
System.out.println("Precision : " + precision);
VSOP87.setDataPath(DATA_PATH);
int i;
Body b = new Body(MERCURY);
double[] dates = new double[nbDates];
// build an array of dates - centered on baseJD
for (i = 0; i < nbDates; i++){
dates[i] = baseJD - (double)(nbDates/2 + i);
}
// get the time
long begTime = System.currentTimeMillis();
for (i = 0; i < nbDates; i++){
VSOP87.calcCoord(dates[i], b, precision, true);
}
long endTime = System.currentTimeMillis();
long deltaT = endTime - begTime;
double timeForOne = (double)deltaT/(double)nbDates;
System.out.println("deltaT = " + deltaT);
System.out.println("timeForOne = " + timeForOne);
}
catch(Exception e){
e.printStackTrace();
System.exit(0);
}
}// end testPerf
//=================================================================================
// PRIVATE METHODS
//=================================================================================
//******************************** getBDLResults() *****************************
private static void getBDLResults(String checkFile){
try{
bdlT = new JEphemTest[_nbPlan][_nbJD];
int iJD, iPlanet, iCoord; // main indexes
String line = new String();
// FileInputStream fis = new FileInputStream(new File("test_jephem.htm"));
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(checkFile)));
String strTmp; // temporary variable
int iSpace; // temporary variable
int planetNumber; // number of the planet, corresponding to VSOP87.java
// for a couple (planet, JD, a group of 4 lines is read
for (iPlanet = 0; iPlanet < _nbPlan; iPlanet ++){
for (iJD = 0; iJD < _nbJD; iJD ++){
bdlT[iPlanet][iJD] = new JEphemTest();
// *** 1.1 Read comment line
line = lnr.readLine().trim();
// get rid of "VSOP87X"
iSpace = line.indexOf(" ");
line = line.substring(iSpace).trim();
// get planet name
iSpace = line.indexOf(" ");
strTmp = line.substring(0, iSpace).trim();
// @better2
planetNumber = 0;
if (strTmp.equals("MERCURY")) planetNumber = 2;
else if (strTmp.equals("VENUS")) planetNumber = 3;
else if (strTmp.equals("EARTH")) planetNumber = 4;
else if (strTmp.equals("MARS")) planetNumber = 5;
else if (strTmp.equals("JUPITER")) planetNumber = 6;
else if (strTmp.equals("SATURN")) planetNumber = 7;
else if (strTmp.equals("URANUS")) planetNumber = 8;
else if (strTmp.equals("NEPTUNE")) planetNumber = 9;
//else error;
bdlT[iPlanet][iJD].body.setIndex(planetNumber);
// get JD
line = line.substring(iSpace).trim();
iSpace = line.indexOf(" ");
strTmp = line.substring(2, iSpace).trim(); // 2 because of "JD" in front of the number
bdlT[iPlanet][iJD].jd = Double.parseDouble(strTmp);
// get strDate
line = line.substring(iSpace).trim();
bdlT[iPlanet][iJD].strDate = line;
// *** 1.2 line containing positions and velocities
for (int i=0; i<2; i++){
line = lnr.readLine().trim();
// get rid of "x"
iSpace = line.indexOf(" ");
line = line.substring(iSpace).trim();
// get x
iSpace = line.indexOf(" ");
strTmp = line.substring(0, iSpace).trim();
bdlT[iPlanet][iJD].body.setCoord(0 + 3*i, Double.parseDouble(strTmp));
line = line.substring(iSpace).trim();
// get rid of "au"
iSpace = line.indexOf(" ");
line = line.substring(iSpace).trim();
// get rid of "y"
iSpace = line.indexOf(" ");
line = line.substring(iSpace).trim();
// get y
iSpace = line.indexOf(" ");
strTmp = line.substring(0, iSpace).trim();
bdlT[iPlanet][iJD].body.setCoord(1 + 3*i, Double.parseDouble(strTmp));
line = line.substring(iSpace).trim();
// get rid of "au"
iSpace = line.indexOf(" ");
line = line.substring(iSpace).trim();
// get rid of "z"
iSpace = line.indexOf(" ");
line = line.substring(iSpace).trim();
// get z
iSpace = line.indexOf(" ");
strTmp = line.substring(0, iSpace).trim();
bdlT[iPlanet][iJD].body.setCoord(2 + 3*i, Double.parseDouble(strTmp));
} // end for i = 1 to 2
// *** 1.2 empty line
line = lnr.readLine();
} // end for iJD
} // end for iPlanet
lnr.close();
// fis.close();
}
catch(Exception e){
System.out.println("Exception" + e.toString());
e.printStackTrace();
System.exit(0);
}
}// end getBDLResults()
//******************************** getJEphemResults() **************************
private static void getJEphemResults(){
//if (testedFilter == FILTER_FULL) VSOP87.setDataPath(DATA_PATH);
VSOP87.setDataPath(DATA_PATH);
int iJD, iPlanet, iCoord; // main indexes
jephemT = new JEphemTest[_nbPlan][_nbJD];
startCalcTime = new Date();
for (iPlanet = 0; iPlanet < _nbPlan; iPlanet ++){
for (iJD = 0; iJD < _nbJD; iJD ++){
jephemT[iPlanet][iJD] = new JEphemTest(bdlT[iPlanet][iJD].body.getIndex());
jephemT[iPlanet][iJD].jd = bdlT[iPlanet][iJD].jd;
jephemT[iPlanet][iJD].strDate = bdlT[iPlanet][iJD].strDate;
//System.out.println("Computing : "
// + planetNames[jephemT[iPlanet][iJD].body.getIndex()]
// + ", " + jephemT[iPlanet][iJD].strDate);
// ***** Call to JEphem *****
double precision = 0;
if (testedFilter == FILTER_FULL) precision = 0;
if (testedFilter == FILTER_BDL || testedFilter == FILTER_JEPHEM) precision = 4;
try{
VSOP87.calcCoord(jephemT[iPlanet][iJD].jd, jephemT[iPlanet][iJD].body, precision, true);
}
catch(Exception e){
System.out.println("error in VSOP87.calcCoord() iPlanet = " + iPlanet
+ " jd = " + jephemT[iPlanet][iJD].jd);
System.out.println(" " + e.toString());
}
} // end for iJD
} // end for iPlanet
endCalcTime = new Date();
}// end getJEphemResults()
//******************************** getDifferences() **************************
/** Gets the differences between full and truncated versions. */
private static void getDifferences(){
int iJD, iPlanet, iCoord; // main indexes
int retCode;
double tmp;
delta = new double[_nbPlan][_nbJD][NB_COORD];
deltaNormPos = new double[_nbPlan][_nbJD];
deltaNormVel = new double[_nbPlan][_nbJD];
deltaMaxNormPos = new double[_nbPlan];
deltaMaxNormVel = new double[_nbPlan];
for (iPlanet = 0; iPlanet < _nbPlan; iPlanet ++){
deltaMaxNormVel[iPlanet] = deltaMaxNormPos[iPlanet] = 0.0;
for (iJD = 0; iJD < _nbJD; iJD ++){
tmp = 0;
// for positions
for (iCoord = 0; iCoord < NB_COORD/2; iCoord ++){
delta[iPlanet][iJD][iCoord] = Math.abs(jephemT[iPlanet][iJD].body.getCoord(iCoord) -
bdlT[iPlanet][iJD].body.getCoord(iCoord));
tmp += delta[iPlanet][iJD][iCoord] * delta[iPlanet][iJD][iCoord];
}
deltaNormPos[iPlanet][iJD] = Math.sqrt(tmp);
if (deltaNormPos[iPlanet][iJD] > deltaMaxNormPos[iPlanet])
deltaMaxNormPos[iPlanet] = deltaNormPos[iPlanet][iJD];
// for velocities
tmp = 0;
for (iCoord = NB_COORD/2; iCoord < NB_COORD; iCoord ++){
delta[iPlanet][iJD][iCoord] = Math.abs(jephemT[iPlanet][iJD].body.getCoord(iCoord) -
bdlT[iPlanet][iJD].body.getCoord(iCoord));
tmp += delta[iPlanet][iJD][iCoord] * delta[iPlanet][iJD][iCoord];
}
deltaNormVel[iPlanet][iJD] = Math.sqrt(tmp);
if (deltaNormVel[iPlanet][iJD] > deltaMaxNormVel[iPlanet])
deltaMaxNormVel[iPlanet] = deltaNormVel[iPlanet][iJD];
} // end for iJD
} // end for iPlanet
}// end getDifferences()
//******************************** buildOutputBeginning() **************************
private static String buildOutputBeginning(){
String strRes = new String();
strRes += "<HTML>" + LS;
strRes += "<HEAD>" + LS;
strRes += "<STYLE>" + LS;
strRes += "TABLE {text-align:center}" + LS;
strRes += "TABLE.Small {font-size:smaller}" + LS;
strRes += "</STYLE>" + LS;
strRes += "</HEAD>" + LS;
strRes += "<BODY>" + LS;
strRes += "<CENTER><H1>JEphem precision tests</H1>" +LS;
strRes += "Generated by <CODE>TestVSOP87.java</CODE></CENTER>" + LS;
strRes += "<BR>Version of JEphem used : <B>";
if(testedFilter == FILTER_FULL)
strRes += "full precision";
if(testedFilter == FILTER_BDL || testedFilter == FILTER_JEPHEM)
strRes += "truncated series";
strRes += ".</B>" + LS;
strRes += "<BR>Time to perform " + Integer.toString(_nbPlan * _nbJD) + " computations : "
+ Double.toString((endCalcTime.getTime() - startCalcTime.getTime()) / 1000.0)
+ " seconds.<BR>" + LS + LS;
strRes += "<BR>In this page : " + LS;
if (strOutputType.charAt(2) == '1')
strRes += "Summary " + LS; strRes += "<A HREF=\"#Summary\">Summary</A> " + LS;
if (strOutputType.charAt(1) == '1')
strRes += "Difference tables " + LS; strRes += "<A HREF=\"#DiffByPlan\">Difference tables</A> " + LS;
if (strOutputType.charAt(0) == '1')
strRes += "Detailed tests " + LS; strRes += "<A HREF=\"#DetailByJD\">Detailed tests</A> " + LS;
return strRes;
}// end buildOutputBeginning()
//******************************** buildOutputDetailByJD() *********************
/** Generates tables showing all the results, grouped by julian days */
private static void buildOutputDetailByJD(FileOutputStream fos){
try{
int iJD, iPlanet, iCoord; // main indexes
String strRes = new String();
strRes += LS + LS + "<!-- ************************************************** -->" + LS;
strRes += "<H2><A NAME=\"DetailByJD\"></A>Detailed tables by JD</H2>" + LS;
// for each julian day
for (iJD = 0; iJD < _nbJD; iJD ++){
// title
strRes += "<TABLE CLASS=\"Small\" BORDER = \"1\">" + LS;
strRes += "<TR><TD COLSPAN = \"2\"></TD>" + LS;
strRes += "<TD COLSPAN = \"6\"><B>" + LS;
strRes += "JD = " + Double.toString(bdlT[0][iJD].jd); // 0 because JDs are the same
strRes += " " + bdlT[0][iJD].strDate; //for different planets
strRes += "</B></TD></TR>" + LS;
// legends
strRes += "<TR><TD COLSPAN = \"2\">Variables</TD>" + LS;
for (int i=0; i < NB_COORD; i++){
strRes += "<TD>" + coordNames[i] + " (" + strUnitPos[i] + ")"
+ "</TD>" + LS;
}
strRes += "</TR>" + LS;
//for each planet
for (iPlanet = 0; iPlanet < _nbPlan; iPlanet ++){
//System.out.println(" - iJD = " + iJD + "iPlanet = " + iPlanet);
// write planet name
strRes += "<TR BGCOLOR =\"#FAD6AD\">";
strRes += "<TD ROWSPAN = \"3\">";
for (int i = 0; i < 3; i++)
strRes += planetNames[bdlT[iPlanet][0].body.getIndex()].substring(i, i+1) + "<BR>";
strRes += "</TD>" + LS;
// *** BDL line
strRes += "<TD>BDL</TD>" + LS;
for (iCoord = 0; iCoord < NB_COORD; iCoord ++){
strRes += "<TD>"
+ NF.format(bdlT[iPlanet][iJD].body.getCoord(iCoord))
+ "</TD>" + LS;
} // end for iCoord
strRes += "</TR>" + LS;
// *** JEphem line
strRes += "<TR>" + LS;
strRes += "<TD>JEphem full</TD>" + LS;
for (iCoord = 0; iCoord < NB_COORD; iCoord ++){
strRes += "<TD>"
+ NF.format(jephemT[iPlanet][iJD].body.getCoord(iCoord))
+ "</TD>" + LS;
} // end for iCoord
strRes += "</TR>" + LS;
// *** Difference JEphem - BDL line
strRes += "<TR BGCOLOR =\"yellow\">" + LS;
strRes += "<TD>|J. full - BDL|</TD>" + LS;
for (iCoord = 0; iCoord < NB_COORD; iCoord ++){
strRes += "<TD>"
+ NF.format(delta[iPlanet][iJD][iCoord])
+ "</TD>" + LS;
} // end for iCoord
strRes += "</TR>" + LS;
fos.write(strRes.getBytes());
strRes ="";
} // end for each planet
strRes += "<TABLE/><BR><BR>" + LS;
strRes += "<BR>" + LS;
} // end for each JD
fos.write(strRes.getBytes());
}
catch(Exception e){
System.out.println("Exception" + e.toString());
e.printStackTrace();
System.exit(0);
}
}// end buildOutputDetailByJD()
//******************************** buildOutputDiffByPlanet() *********************
private static void buildOutputDiffByPlanet(FileOutputStream fos){
try{
int iJD, iPlanet, iCoord; // main indexes
String strRes = new String("");
double[][] deltaMax = new double[_nbPlan][NB_COORD];
strRes += LS + LS + "<!-- ************************************************** -->" + LS;
strRes += "<H2><A NAME=\"DiffByPlan\"></A>Differences tables by planet</H2>" + LS;
// for each planet
for (iPlanet = 0; iPlanet < _nbPlan; iPlanet ++){
// title
strRes += "<TABLE CLASS=\"2\" BORDER = \"1\">" + LS;
strRes += "<TR><TD></TD>" + LS;
strRes += "<TD COLSPAN = \"8\"><B>" + LS;
strRes += planetNames[bdlT[iPlanet][0].body.getIndex()];
strRes += "</B></TD></TR>" + LS;
// coordinate legends
strRes += "<TR><TD>Dates</TD>" + LS;
for (int i = 0; i < NB_COORD; i++){
strRes += "<TD>Delta " + coordNames[i] + " (" + strUnitPos[i]
+ ")</TD>" + LS;
if (i == 2)
strRes += "<TD>Norm (" + strUnitPos[0]
+ ")</TD>" + LS;
}
strRes += "<TD>Norm (" + strUnitPos[NB_COORD - 1]
+ ")</TD>" + LS;
strRes += "</TR>" + LS;
//for each julian day, write a line of data
for (iJD = 0; iJD < _nbJD; iJD ++){
//System.out.println(" - iJD = " + iJD + "iPlanet = " + iPlanet);
strRes += "<TR>" + LS;
// write date
int idx = bdlT[iPlanet][iJD].strDate.indexOf(" ");
strRes += "<TD>" + bdlT[iPlanet][iJD].strDate.substring(0, idx).trim()
+ "</TD>" + LS;
// write data for delta pos and vel
for (iCoord = 0; iCoord < NB_COORD; iCoord ++){
strRes += "<TD>" + NF.format(delta[iPlanet][iJD][iCoord])
+ "</TD>" + LS;
if (delta[iPlanet][iJD][iCoord] > deltaMax[iPlanet][iCoord])
deltaMax[iPlanet][iCoord] = delta[iPlanet][iJD][iCoord];
if (iCoord==2)
// write data for delta norm pos
strRes += "<TD><B>" + NF.format(deltaNormPos[iPlanet][iJD])
+ "</B></TD>" + LS;
} // end for iCoord
// write data for delta norm vel
strRes += "<TD><B>" + NF.format(deltaNormVel[iPlanet][iJD])
+ "</B></TD>" + LS;
strRes += "</TR>" + LS;
fos.write(strRes.getBytes());
strRes ="";
} // end for each JD
// *** Delta max
strRes += "<TR BGCOLOR = \"yellow\"><TD>Delta max</TD>" + LS;
for (iCoord = 0; iCoord < NB_COORD; iCoord ++){
strRes += "<TD>" + NF.format(deltaMax[iPlanet][iCoord])
+ "</TD>" + LS;
if (iCoord==2)
// write data for delta max norm pos
strRes += "<TD><B>" + NF.format(deltaMaxNormPos[iPlanet])
+ "</B></TD>" + LS;
} // end for iCoord
// write data for delta max norm vel
strRes += "<TD><B>" + NF.format(deltaMaxNormVel[iPlanet])
+ "</B></TD>" + LS;
strRes += "</TR>" + LS;
strRes += "<TABLE/>" + LS;
// *** Delta max for the norms
int indPla = bdlT[iPlanet][0].body.getIndex();
strRes += "Delta max of vector norms (built only with delta max) for <B>"
+ planetNames[indPla] + "</B> :";
strRes += "<BR><B>Position</B> : " + NF.format(deltaMaxNormPos[iPlanet]) + " au = "
+ NF2.format(deltaMaxNormPos[iPlanet] * KM_PER_AU) + " km.";
strRes += "<BR>Seen from Earth, this represents an error of <B>"
+ NF2.format(calcGeocentricError(deltaMaxNormPos[iPlanet], indPla))
+ "</B> arc sec.";
strRes += "<BR><B>Velocity</B> : " + NF.format(deltaMaxNormVel[iPlanet]) + " au/d = "
+ NF2.format(deltaMaxNormVel[iPlanet] * KM_PER_AU * 1000 / 84600) + " m/s.";
strRes += "<BR><BR>" + LS;
} // end for each planet
fos.write(strRes.getBytes());
}
catch(Exception e){
System.out.println("Exception" + e.toString());
e.printStackTrace();
System.exit(0);
}
}// end buildOutputDiffByPlanet()
//******************************** buildOutputSummary() ************************
private static void buildOutputSummary(FileOutputStream fos){
int iPlanet;
String strRes = new String("");
try{
strRes += LS + LS + "<!-- ************************************************** -->" + LS;
strRes += "<H2><A NAME=\"Summary\"></A>Summary</H2>" + LS;
strRes += "<TABLE BORDER = \"1\" BGCOLOR=\"#FFFFCC\">" + LS;
strRes += "<TR><TD></TD>" + LS;
strRes += "<TD COLSPAN = \"2\"><B>Positions</B></TD>" + LS;
strRes += "<TD><B>Velocities</B></TD></TR>" + LS;
strRes += "<TR><TD></TD><TD>Norm of<BR>delta max</TD>" + LS;
strRes += "<TD>Geocentric<BR>angular error</TD>" + LS;
strRes += "<TD>Norm of<BR>delta max</TD></TR>" + LS;
int indPla;
for(iPlanet = 0; iPlanet < _nbPlan; iPlanet ++){
indPla = bdlT[iPlanet][0].body.getIndex();
strRes += "<TR><TD>" + planetNames[bdlT[iPlanet][0].body.getIndex()] + "</TD>" + LS;
// norm of delta max pos
strRes+= "<TD>" + NF.format(deltaMaxNormPos[iPlanet]) + " au<BR>" + LS;
strRes+= NF2.format(deltaMaxNormPos[iPlanet] * KM_PER_AU) + " km</TD>" + LS;
// geocentric error
strRes += "<TD><B>"
+ NF2.format(calcGeocentricError(deltaMaxNormPos[iPlanet], indPla))
+ " \"</B></TD>" + LS;
// norm of delta max vel
strRes+= "<TD>" + NF.format(deltaMaxNormVel[iPlanet]) + " au/s<BR>" + LS;
strRes+= NF2.format(deltaMaxNormVel[iPlanet] * KM_PER_AU * 1000/84600) + " m/s - " + LS;
strRes+= NF2.format(deltaMaxNormVel[iPlanet] * KM_PER_AU * 1000/84600 * 3.6)
+ " km/h</TD>" + LS;
strRes+= "</TR>" + LS;
}
strRes += "</TABLE><BR><BR>";
fos.write(strRes.getBytes());
}
catch(Exception e){
System.out.println("Exception" + e.toString());
e.printStackTrace();
System.exit(0);
}
}// end buildOutputSummary()
//**************************** calcGeocentricError() **************
/******************************************************************
Given the norm of a vector representing the error on a position, calculates the angular error
as seen from Earth. Computation done for a case when the planet is in its nearest position from
Earth (worst case).
@param norm Norm of the error vector, in a<B>u</B>.
@param indPla Index of the planet, using constants of <CODE>ISolarSystem.java</CODE>.
@return Error as seen from Earth, in <B>arcseconds</B>.
*****************************************************************/
private static double calcGeocentricError(double norm, int indPla){
double d; // dist(Earth planet) in au.
if (indPla == MERCURY || indPla == VENUS)
d = 1.0 - a0s[indPla];
else if(indPla == EARTH)
d = a0s[indPla];
else
d = a0s[indPla] - 1.0;
return Math.toDegrees(Math.atan(norm / d)) * 3600.0;
}// end calcGeocentricError()
//=================================================================================
// AUXILIARY CLASSES
//=================================================================================
/******************************************************************
Class internal to <A HREF="TestVSOP87.html">TestVSOP87</A> containing results of a computation for
a planet and a JD.
<BR>
@author Thierry Graff
@history jan 21 2001 creation.
@todo remove strDate when a method to format date from JD is available.
@todo other constructors
@todo link in the comment for Body
*****************************************************************/
static class JEphemTest{
/** Julian day concerned by this test. */
double jd;
/** Date representation od the julian day concerned by this test. */
String strDate;
/** index of the planet concerned by this test (referring to jephem.astro.SolarSystem
constants). */
//int planetIndex;
/** results of the test */
//double[] coords;
// Repeats a fields of tig.GeneralConstants
private static final int NO_SPECIF = -1;
/** jephem.astro.Body concerned by this test. */
Body body;
/** Constructor just initializing <CODE>this.body</CODE>. */
public JEphemTest(){
this.body = new Body(NO_SPECIF);
}
/** Constructor just initializing coords <CODE>this.body</CODE>.*/
public JEphemTest(int planetIndex){
this.body = new Body(planetIndex);
}
}//end class JEphemTest
}//end class TestVSOP87