//*********************************************************************************
// class AnalyseVSOP87 // default package
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
import java.io.*;
import java.lang.reflect.Method;
/******************************************************************
Contains methods used to analyze VSOP87 data classes.
<BR>This class is not used by JEphem, it was developped to include the generated table in a <A HREF="../../../ephemeris/et320buildVSOP_en.htm" TARGET="_top">page of JEphem's site</A>.
<BR>In this class, when arrays characterizing planetary data were needed (ex : "planetNames"), the indexes of <CODE>jephem.astro.SolarSystem.java</CODE> were used.
@author Thierry Graff
@history mar 30 2001 : Creation from BuildVSOP87.
@todo In getNbTerms, generate java classes, instead of .txt. If the name of this method changes,
change also javadoc comment of buildNbTermsTable
@todo getNbTerms should be renamed and generate compilable java classes
@todo Clean class fields coming from BuildVSOP87
*****************************************************************/
public class AnalyseVSOP87{
// planet names ; indexes correspond to jephem.astro.ISolarSystem.java constants.
private static String[] planetNames = {"", "", "Mercury", "Venus", "Earth", "Mars", "Jupiter",
"Saturn", "Uranus", "Neptune"};
private static int NB_PLANETS = 8;
private static int INDEX_MERCURY = 2;
private static int INDEX_NEPTUNE = 10;
static int SPACE_CODE = 32; // Unicode code of " ".
static int A_CODE = 10; // Unicode code of "A".
static int BEGIN_ABC = 82; // Index between terms K and A in a data line (in a BDL file).
static int MAX_T = 5; // Maximum degree of time in VSOP87 BDL files.
// semi-major axis ; index corresopnd to jephem.astro.ISolarSystem.java constants.
static double[] a0s = {0.0, 0.0, 0.39, 0.72, 1.00, 1.52, 5.20, 9.55, 19.22, 30.11}; // a.u.
// eccentricities ; index corresopnd to jephem.astro.ISolarSystem.java constants.
static double[] eccs = {0.0, 0.0, 0.21, 0.01, 0.02, 0.09, 0.05, 0.06, 0.05, 0.01};
// Maximal geocentric angular error admissible for a planet (result of calcAlphaMax).
// Valid for versions A and C
// Index corresopnd to jephem.astro.ISolarSystem.java constants.
static double alphaMax[] = {0.0, 0.0, 0.5, 0.1, 0.2, 0.4, 0.9, 0.9, 0.9, 0.9}; // in arc seconds
//=================================================================================
// METHODS
//=================================================================================
//**************** main ************************
public static void main(String[] args){
buildNbTermsTable(args[0], args[1]);
//getNbTerms(args[0]);
//calcErrMax();
//calcAlphaMax(args[0], args[1]);
//getBDLCommentLines();
}// end main
//**************** getNbTerms ************************
/** This method takes in current directory data classes (.java) and builds two files :
<LI><CODE>'prefix'__nbTerms.txt</CODE>, containing nbTerms arrays</LI>,
<LI><CODE>'prefix'__retained.txt</CODE>, containing comment lines of data[][]</LI>.
The purpose is to compare generated data classes with XEphem classes and original BDL files.
<BR>Names of data classes must be : <CODE>strPrefix_yyy</CODE>, where <CODE>yyy</CODE> is
planet name.
@param strPrefix beginning of names of files to analyze (ex <CODE>DataVSOP87A_Full</CODE>).
*/
public static void getNbTerms(String strPrefix){
String ls = System.getProperty("line.separator");
FileOutputStream fosNbTerms = null;
// FileOutputStream fosRetained = null;
LineNumberReader lnr = null;
String planetName = new String();
String inputFileName = new String();
String outputNbTerms = strPrefix + "__nbTerms.txt";
// String outputRetained = strPrefix + "__retained.txt";
String line = new String();
String strRes = new String();
boolean keepOn;
try{
fosNbTerms = new FileOutputStream(new File(outputNbTerms));
// fosRetained = new FileOutputStream(new File(outputRetained));
strRes += "*** nbTerms for " + strPrefix + " ***" + ls + ls;
fosNbTerms.write(strRes.getBytes());
for (int i = 2; i < 10; i++){
// find data class file name.
inputFileName = strPrefix + "_" + planetNames[i] + ".java";
System.out.println("Analyzing " + inputFileName);
lnr = new LineNumberReader(new FileReader(new File(inputFileName)));
// *** 1 - Write strPrefix__nbTerms.txt
strRes = "";
// read until the beginning of nbTerms array is found
keepOn = true;
while(keepOn){
line = lnr.readLine();
if (line.indexOf("nbTerms[][]") != -1) keepOn = false;
}
strRes += " int[][] nbTerms_" + planetNames[i] + " = {" + ls;
// copy until the end of nbTerms[][] is found.
keepOn = true;
while(keepOn){
line = lnr.readLine();
if (line.indexOf("};") != -1){
keepOn = false;
strRes += " }; // end nbTerms_" + planetNames[i] + "[][]" + ls;
}
else
strRes += line + ls;
}
strRes += ls;
fosNbTerms.write(strRes.getBytes());
/*
// *** 2 - Write in strPrefix__retained.txt
strRes = "";
// read until the beginning of data array is found
keepOn = true;
while(keepOn){
line = lnr.readLine();
if (line.indexOf("data[][]") != -1) keepOn = false;
}
strRes += "****************** " + planetNames[i] + " ******************" + ls;
// write only comment and blank lines
keepOn = true;
while(keepOn){
line = lnr.readLine();
if (line.indexOf("end data[][]") != -1) keepOn = false;
else{
if (! line.trim().startsWith("{"))
strRes += line + ls;
}
}
fosRetained.write(strRes.getBytes());
*/
lnr.close();
}// end for i = 2 to 9
fosNbTerms.close();
// fosRetained.close();
}
catch(Exception ex){
System.out.println("Exception" + ex.toString());
ex.printStackTrace();
System.exit(0);
}
}// end getNbTerms
//**************** buildNbTermsTable ************************
/** Once nbTerm classes have been generated with {@link #getNbTerms(String) getNbTerms},
the purpose is to generate an HTML table comparing these classes.
<BR>For each planet, a sum is done for each number of terms.
<BR><BR>To work, compiled nbTerm classes (ex : <CODE>DataVSOP87A__nbTerms.class</CODE>) MUST
be in the classpath.
@param strVersion : contains coma-separated names of the versions to compare
<BR>(ex : "<CODE>VSOP87A_Full,VSOP87A,VSOP87C</CODE>")
<BR>The program will search for classes with names corresponding to the output of
<CODE>getNbTerms()</CODE> (in the example : <CODE>DataVSOP87A_Full__nbTerms.class</CODE>,
<CODE>DataVSOP87A__nbTerms.class</CODE>, <CODE>DataVSOP87D__nbTerms.class</CODE>).
@param strTitles : contains the titles which will appear in the tables
<BR>(ex : "<CODE>(BDL),(JEphem),(XEphem)</CODE>").
<BR>There MUST be the same number of elements in <CODE>strVersions</CODE> and strTitles.
*/
public static void buildNbTermsTable(String strVersions, String strTitles){
String ls = System.getProperty("line.separator");
//auxiliary variables
String strTmp;
int i, j, k, l;
//*** Argument parsing ***
int nbVersions = 0;
int idxComa;
// calculate nbVersions from the number of comas in strVersion
strTmp = strVersions;
idxComa = strTmp.indexOf(',');
while(idxComa !=-1){
nbVersions ++;
strTmp = strTmp.substring(idxComa + 1);
idxComa = strTmp.indexOf(',');
}
nbVersions ++;
System.out.println("nbVersions = " + nbVersions);
// Check that there is the same number of comas in strTitles
strTmp = strTitles;
int tmp = 0;
idxComa = strTmp.indexOf(',');
while(idxComa !=-1){
tmp ++;
strTmp = strTmp.substring(idxComa + 1);
idxComa = strTmp.indexOf(',');
}
tmp ++;
if (tmp != nbVersions){
System.out.println("Both arguments (version names and tiles) must have the same number of"
+ " comas\nUnable to process");
System.exit(0);
}
//*** build the arrays of classnames and headings to be displayed
String[] strHeadings = new String[nbVersions];
String[] strClasses = new String[nbVersions];
strClasses = AnalyseVSOP87.parse(strVersions);
strHeadings = AnalyseVSOP87.parse(strTitles);
for (i = 0; i<nbVersions; i++){
strHeadings[i] = "<CENTER>" + strClasses[i] +"<BR>(" + strHeadings[i] + ")</CENTER>";
strClasses[i] = "Data" + strClasses[i] + "__nbTerms";
System.out.println("strHeadings[i] = " + strHeadings[i]);
System.out.println("strClasses[i] = " + strClasses[i]);
}
//*** Get the data from classes xxx_nbTerms.class, using reflectivity
// these classes must be in the classpath***
// And make the sums that will be displayed
try{
int[][] nbTerms = new int [nbVersions][NB_PLANETS];
int[] totalTerms = new int [nbVersions]; // total nb of terms for this version
int[][] terms = new int[3][5] ; // details of terms for a planet
for(i = 0; i < nbVersions; i++){
Class dataClass = Class.forName(strClasses[i]);
for (j = INDEX_MERCURY; j < INDEX_NEPTUNE; j++){
terms = (int[][])dataClass.getDeclaredField("nbTerms_" + planetNames[j]).get(null);
for(k = 0; k < 3; k++){
for(l = 0; l < 6; l++){
nbTerms[i][j - INDEX_MERCURY] += terms[k][l];
totalTerms[i] += terms[k][l];
}
}
}// end for j
}// end for i
//*** Build the HTML output
String strRes = "";
// Beginning
FileOutputStream fosNbTerms = new FileOutputStream(new File("result.htm"));
strRes += "<HTML><BODY>" + ls;
strRes += "<TABLE BORDER = \"1\">" + ls;
// First row, for titles
strRes += "<TR><TD></TD>" + ls;
for (i = 0; i < nbVersions; i++)
strRes+= "<TD><B>" + strHeadings[i] + "</B></TD>";
strRes += "</TR>" + ls;
// Data Rows, containing nb of terms
for (i = INDEX_MERCURY; i < INDEX_NEPTUNE; i++){
strRes += "<TR>" + ls;
strRes += "<TR><TD><CENTER>" + planetNames[i] + "</CENTER></TD>" + ls;
for(j = 0; j < nbVersions; j++){
strRes += "<TD><CENTER>" + nbTerms[j][i - INDEX_MERCURY] + "</CENTER></TD>" + ls;
}
strRes += "</TR>" + ls;
}
// Data Rows, containing nb of terms
strRes += "<TR>" + ls;
strRes += "<TR><TD><CENTER><B>Total</B></CENTER></TD>" + ls;
for(j = 0; j < nbVersions; j++)
strRes += "<TD><CENTER><B>" + totalTerms[j] + "</B></CENTER></TD>" + ls;
strRes += "</TR>" + ls;
// End
strRes += "</TABLE>" + ls;
strRes += "</BODY></HTML>" + ls;
fosNbTerms.write(strRes.getBytes());
fosNbTerms.close();
}
catch(Exception ex){
System.out.println("Exception" + ex.toString());
ex.printStackTrace();
System.exit(0);
}
}// end buildNbTermsTable
//******************* parse(String s) **************
/**********************************************************
// REFERENCE IMPLEMENTATION IN tig.util.Util.java
// used by buildNbTermsTable
*****************************************************************/
private static String[] parse(String s){
//System.out.println("s = " + s);
int curPos=0, i=0;
int comaPos=s.indexOf(',', curPos);
//1er passage, détermination de la longueur du tableau réultat res[]
while(comaPos!=-1){
curPos=comaPos+1;
comaPos=s.indexOf(',', curPos);
i++;
}
//2ème passage, remplissage de res[]
//System.out.println("2eme passage");
String[] res = new String[i+1];
curPos=0;
i=0;
comaPos=s.indexOf(',', curPos);
while(comaPos!=-1){
res[i]=s.substring(curPos, comaPos).trim();
//System.out.println("res[" + i + "] = " + res[i] + " ; comaPos = " + comaPos);
curPos=comaPos+1;
comaPos=s.indexOf(',', curPos);
i++;
}
res[i]=s.substring(curPos, s.length()).trim();
//System.out.println("res[" + i + "] = " + res[i] + " ; comaPos = " + comaPos);
return res;
}//end parse(String s)
//**************** getBDLCommentLines() ************************
/** Produces an output with only comment lines of BDL files.
<BR>Method used to check validity of nbTerms arrays in classes "DataVSOP87C_Full_xxx".
<BR>Input files must be in the current directory
*/
public static void getBDLCommentLines(){
String ls = System.getProperty("line.separator");
String strOutputFile = "DataVSOP87C_Comments.txt";
String[] strInputFiles = {"VSOP87C.ear.txt", "VSOP87C.jup.txt",
"VSOP87C.mar.txt", "VSOP87C.mer.txt",
"VSOP87C.nep.txt", "VSOP87C.sat.txt",
"VSOP87C.ura.txt", "VSOP87C.ven.txt"
};
FileOutputStream fos = null;
LineNumberReader lnr = null;
try{
fos = new FileOutputStream(new File(strOutputFile));
String line = new String();
for (int i = 0; i < strInputFiles.length ; i++){
lnr = new LineNumberReader(new FileReader(new File(strInputFiles[i])));
while((line = lnr.readLine()) != null){
if (line.trim().startsWith("VSOP87")){
fos.write(line.getBytes());
fos.write(ls.getBytes());
}
} // end while((line = lnr.readLine()) != null)
fos.write(ls.getBytes());
lnr.close();
lnr = null;
} // end for i < strInputFiles.length
fos.close();
}
catch(Exception e){
System.out.println("Exception" + e.toString());
e.printStackTrace();
System.exit(0);
}
}// end getBDLCommentLines
//**************** calcAlphaMax ************************
/** Intermediate calculation to know maximal geocentric angular error admissible for a planet
to finally get 1 arcsecond of precision.
@param strAlpha0 and strAlpha1 represent the values in arc seconds
*/
public static void calcAlphaMax(String strAlpha0, String strAlpha1){
double alpha0 = Double.parseDouble(strAlpha0);
double alpha1 = Double.parseDouble(strAlpha1);
alpha0 = Math.toRadians(alpha0/3600.0);
alpha1 = Math.toRadians(alpha1/3600.0);
double aE = a0s[4]; // earth semi-major axis
double eccE = eccs[4]; // earth eccentricity. Could be bettered by calculating eccP and eccE
// in validity interval, and take max / min values.
double res = 0; // = SE/EP
double alpha = 0;
for(int pl = 2; pl < 10; pl++){ // pl = planetIndex
if (pl == 4) continue;
double aP = a0s[pl]; // planet semi-major axis
double eccP = eccs[pl]; // planet eccentricity.
switch (pl){
case 2:
case 3:
res = aE * (1 + eccE) / (aE*(1 - eccE) - aP*(1 + eccP));
break;
case 4:
break;
default:
res = aE * (1 + eccE) / (aP*(1 - eccP) - aE*(1 + eccE));
break;
}
alpha = alpha0 + Math.atan(res * Math.tan(alpha1));
alpha = Math.toDegrees(alpha) * 3600.0;
System.out.println(planetNames[pl] + " : " + alpha);
} // end for pl
}// end calcAlphaMax
//**************** calcErrMax ************************
/** Calculation of maximal error in cartesian heliocentric position.
<BR>Results of calcAlphaMax are used (array alphaMax).
<BR>Results written into a file in order to incorporate to VSOP87Transform4.
*/
public static void calcErrMax(){
String ls = System.getProperty("line.separator");
FileOutputStream fos = null;
String strRes = "";
strRes += " double[] errMax = { 0.0, " + ls;
strRes += " 0.0, " + ls;
try{
fos = new FileOutputStream(new File("errMax.txt"));
double errMax = 0;
double v3 = Math.sqrt(3.0);
double aE = a0s[4]; // earth semi-major axis
double eccE = eccs[4]; // earth eccentricity. Could be bettered by calculating eccP and eccE
// in validity interval, and take max / min values.
double res = 0;
double alpha = 0;
for(int pl = 2; pl < 10; pl++){ // pl = planetIndex
double aP = a0s[pl]; // planet semi-major axis
double eccP = eccs[pl]; // planet eccentricity.
double tgAlphaMax = Math.tan(Math.toRadians(alphaMax[pl]/3600.0));
switch (pl){
case 2:
case 3:
errMax = (aE*(1 - eccE) - aP*(1 + eccP)) * tgAlphaMax / v3;
break;
case 4:
errMax = aE*(1 - eccE) * tgAlphaMax / v3;
break;
default:
errMax = (aP*(1 - eccP) - aE*(1 + eccE)) * tgAlphaMax / v3;
break;
}
System.out.println(planetNames[pl] + " : " + errMax);
strRes += " " + Double.toString(errMax) + ", ";
strRes += " // " + planetNames[pl] + ls;
} // end for pl
strRes += " };" + ls;
fos.write(strRes.getBytes());
fos.close();
}
catch(Exception ex){
System.out.println("Exception" + ex.toString());
ex.printStackTrace();
System.exit(0);
}
}// end calcErrMax
}//end class AnalyseVSOP87