/*
VisAD system for interactive analysis and visualization of numerical
data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package visad.data.amanda;
import java.rmi.RemoteException;
import visad.Data;
import visad.FieldImpl;
import visad.FlatField;
import visad.FunctionType;
import visad.Gridded1DSet;
import visad.Gridded3DSet;
import visad.RealTupleType;
import visad.RealType;
import visad.SetType;
import visad.VisADException;
import visad.util.Util;
public abstract class BaseTrack
implements Comparable
{
public static final RealType indexType =
RealType.getRealType("Track_Index");
private static final RealType energyType =
RealType.getRealType("Track_Energy");
public static FunctionType functionType;
public static FunctionType timeSequenceType;
public static FieldImpl missing;
private static FunctionType indexTupleType;
static {
try {
functionType =
new FunctionType(AmandaFile.xyzType,
new RealTupleType(RealType.Time, energyType));
timeSequenceType = new FunctionType(RealType.Time,
new SetType(AmandaFile.xyzType));
Gridded1DSet set = new Gridded1DSet(RealType.Time, new float[1][1], 1);
missing = new FieldImpl(timeSequenceType, set);
} catch (VisADException ve) {
ve.printStackTrace();
functionType = null;
indexTupleType = null;
timeSequenceType = null;
missing = null;
}
}
private static final float LENGTH_SCALE = 1000.0f;
private static final int X_SAMPLE = 0;
private static final int Y_SAMPLE = 1;
private static final int Z_SAMPLE = 2;
private float xstart;
private float ystart;
private float zstart;
private float zenith;
private float azimuth;
private float length;
private float energy;
private float time;
private float maxLength;
private float[] timeSteps;
private float[][] samples;
BaseTrack(float xstart, float ystart, float zstart, float zenith,
float azimuth, float length, float energy, float time)
{
this.xstart = xstart;
this.ystart = ystart;
this.zstart = zstart;
this.zenith = zenith;
this.azimuth = azimuth;
this.length = length;
this.energy = energy;
this.time = time;
timeSteps = null;
samples = null;
}
private static final int compareFloat(float f0, float f1)
{
if (Util.isApproximatelyEqual(f0, f1)) {
return 0;
}
return (f0 < f1 ? -1 : 1);
}
public int compareTo(Object obj)
{
if (obj instanceof BaseTrack) {
return compareTo((BaseTrack )obj);
}
return getClass().getName().compareTo(obj.getClass().getName());
}
public int compareTo(BaseTrack t)
{
int cmp = compareFloat(time, t.time);
if (cmp == 0) {
cmp = compareFloat(xstart, t.xstart);
if (cmp == 0) {
cmp = compareFloat(ystart, t.ystart);
if (cmp == 0) {
cmp = compareFloat(zstart, t.zstart);
if (cmp == 0) {
cmp = compareFloat(zenith, t.zenith);
if (cmp == 0) {
cmp = compareFloat(azimuth, t.azimuth);
if (cmp == 0) {
// negate this since we want to prefer higher-energy tracks
cmp = -compareFloat(energy, t.energy);
if (cmp == 0) {
// negate this since we want to prefer longer tracks
cmp = -compareFloat(length, t.length);
}
}
}
}
}
}
}
return cmp;
}
final void computeSamples(float[] timeSteps)
{
final double degrees2radians = Data.DEGREES_TO_RADIANS;
final double sinZenith = Math.sin(zenith * degrees2radians);
final double cosZenith = Math.cos(zenith * degrees2radians);
final double sinAzimuth = Math.sin(azimuth * degrees2radians);
final double cosAzimuth = Math.cos(azimuth * degrees2radians);
// speed of light (.3 m/nanosecond)
final double SPEED_OF_LIGHT = 0.3 /* * 1000.0 */;
final float timeOrigin, xOrigin, yOrigin, zOrigin;
if (timeSteps.length == 0) {
timeOrigin = time;
xOrigin = xstart;
yOrigin = ystart;
zOrigin = zstart;
samples = null;
} else {
timeOrigin = timeSteps[0];
final double length = (timeOrigin - time) * SPEED_OF_LIGHT;
xOrigin = xstart + (float )(length * sinZenith * cosAzimuth);
yOrigin = ystart + (float )(length * sinZenith * sinAzimuth);
zOrigin = zstart + (float )(length * cosZenith);
samples = new float[timeSteps.length + 1][3];
samples[0][X_SAMPLE] = xOrigin;
samples[0][Y_SAMPLE] = yOrigin;
samples[0][Z_SAMPLE] = zOrigin;
}
for (int i = 0; i < timeSteps.length; i++) {
final double length = (timeSteps[i] - timeOrigin) * SPEED_OF_LIGHT;
float xDelta = (float )(length * sinZenith * cosAzimuth);
float yDelta = (float )(length * sinZenith * sinAzimuth);
float zDelta = (float )(length * cosZenith);
samples[i][X_SAMPLE] = xOrigin + xDelta;
samples[i][Y_SAMPLE] = yOrigin + yDelta;
samples[i][Z_SAMPLE] = zOrigin + zDelta;
}
this.timeSteps = timeSteps;
}
public boolean equals(Object obj) { return compareTo(obj) == 0; }
public final float getEnergy() { return energy; }
public final float getLength() { return length; }
private final float getMaxSample(int sample, float dfltValue)
{
if (samples == null) {
System.err.println("BaseTrack.getMaxSample() called before " +
"BaseTrack.computeSamples()");
Thread.dumpStack();
return dfltValue;
}
float max = samples[0][sample];
for (int i = 1; i < samples.length; i++) {
if (samples[i][sample] > max) max = samples[i][sample];
}
return max;
}
private final float getMinSample(int sample, float dfltValue)
{
if (samples == null) {
System.err.println("BaseTrack.getMinSample() called before " +
"BaseTrack.computeSamples()");
Thread.dumpStack();
return dfltValue;
}
float min = samples[0][sample];
for (int i = 1; i < samples.length; i++) {
if (samples[i][sample] < min) min = samples[i][sample];
}
return min;
}
public final float getXMax() { return getMaxSample(X_SAMPLE, xstart); }
public final float getXMin() { return getMinSample(X_SAMPLE, xstart); }
public final float getYMax() { return getMaxSample(Y_SAMPLE, xstart); }
public final float getYMin() { return getMinSample(Y_SAMPLE, ystart); }
public final float getZMax() { return getMaxSample(Z_SAMPLE, xstart); }
public final float getZMin() { return getMinSample(Z_SAMPLE, zstart); }
abstract FlatField makeData()
throws VisADException;
final FlatField makeData(float maxLength)
throws VisADException
{
float fldLength = length;
if (fldLength > maxLength) {
fldLength = maxLength;
} else if (fldLength != fldLength) {
fldLength = -1.0f;
}
float fldEnergy = energy;
if (fldEnergy != fldEnergy) {
fldEnergy = 1.0f;
}
float zs = (float) Math.sin(zenith * Data.DEGREES_TO_RADIANS);
float zc = (float) Math.cos(zenith * Data.DEGREES_TO_RADIANS);
float as = (float) Math.sin(azimuth * Data.DEGREES_TO_RADIANS);
float ac = (float) Math.cos(azimuth * Data.DEGREES_TO_RADIANS);
float zinc = fldLength * zc;
float xinc = fldLength * zs * ac;
float yinc = fldLength * zs * as;
float[][] locs = {{xstart - LENGTH_SCALE * xinc,
xstart + LENGTH_SCALE * xinc},
{ystart - LENGTH_SCALE * yinc,
ystart + LENGTH_SCALE * yinc},
{zstart - LENGTH_SCALE * zinc,
zstart + LENGTH_SCALE * zinc}};
// construct Field for fit
Gridded3DSet set = new Gridded3DSet(AmandaFile.xyzType, locs, 2);
FlatField field = new FlatField(functionType, set);
float[][] values = {{time, time}, {fldEnergy, fldEnergy}};
try {
field.setSamples(values, false);
} catch (RemoteException re) {
re.printStackTrace();
return null;
}
return field;
}
final FieldImpl makeTimeSequence(float[] timeSteps)
{
if (timeSteps == null || timeSteps.length == 0) {
return null;
}
final double degrees2radians = Data.DEGREES_TO_RADIANS;
// zenith value is the direction from which
// the muon came, not the direction in which it's going,
// so it's 180 degrees off
final double z2 = ((double )zenith + 180.0) % 360.0;
final double a2 = (double )azimuth;
final double sinZenith = Math.sin(z2 * degrees2radians);
final double cosZenith = Math.cos(z2 * degrees2radians);
final double sinAzimuth = Math.sin(a2 * degrees2radians);
final double cosAzimuth = Math.cos(a2 * degrees2radians);
// speed of light (.3 m/nanosecond)
final double SPEED_OF_LIGHT = 0.3;
Gridded3DSet[] sets = new Gridded3DSet[timeSteps.length];
Gridded3DSet missingSet = null;
final float timeOrigin = timeSteps[0];
final float timeFinal = timeSteps[timeSteps.length - 1];
final double baseTime = (timeOrigin - time);
final double baseLength = baseTime * SPEED_OF_LIGHT;
final float xOrigin, yOrigin, zOrigin;
xOrigin = xstart + (float )(baseLength * sinZenith * cosAzimuth);
yOrigin = ystart + (float )(baseLength * sinZenith * sinAzimuth);
zOrigin = zstart + (float )(baseLength * cosZenith);
final double preTime = baseTime - ((timeFinal - timeOrigin) / 2.0);
final double preLength = preTime * SPEED_OF_LIGHT;
final float xPreOrigin, yPreOrigin, zPreOrigin;
xPreOrigin = xstart + (float )(preLength * sinZenith * cosAzimuth);
yPreOrigin = ystart + (float )(preLength * sinZenith * sinAzimuth);
zPreOrigin = zstart + (float )(preLength * cosZenith);
for (int i = 0; i < timeSteps.length; i++) {
final double length = (timeSteps[i] - timeOrigin) * SPEED_OF_LIGHT;
final float xEndpoint, yEndpoint, zEndpoint;
xEndpoint = xOrigin + (float )(length * sinZenith * cosAzimuth);
yEndpoint = yOrigin + (float )(length * sinZenith * sinAzimuth);
zEndpoint = zOrigin + (float )(length * cosZenith);
float[][] locs = {
{ xPreOrigin, xEndpoint },
{ yPreOrigin, yEndpoint },
{ zPreOrigin, zEndpoint },
};
Gridded3DSet subSet;
try {
subSet = new Gridded3DSet(AmandaFile.xyzType, locs, 2);
} catch (VisADException ve) {
ve.printStackTrace();
if (missingSet == null) {
try {
missingSet =
new Gridded3DSet(AmandaFile.xyzType, new float[3][1], 1);
} catch (VisADException ve2) {
ve2.printStackTrace();
}
}
subSet = missingSet;
}
sets[i] = subSet;
}
Gridded1DSet set;
try {
set = new Gridded1DSet(RealType.Time,
new float[][] { timeSteps },
timeSteps.length);
} catch (VisADException ve) {
ve.printStackTrace();
set = null;
}
FieldImpl fld;
try {
fld = new FieldImpl(timeSequenceType, set);
fld.setSamples(sets, false);
} catch (VisADException ve) {
ve.printStackTrace();
fld = missing;
} catch (RemoteException re) {
re.printStackTrace();
fld = missing;
}
return fld;
}
public String toString()
{
String fullName = getClass().getName();
int pt = fullName.lastIndexOf('.');
final int ds = fullName.lastIndexOf('$');
if (ds > pt) {
pt = ds;
}
String className = fullName.substring(pt == -1 ? 0 : pt + 1);
return className + "[" + xstart + "," + ystart + "," + zstart +
" LA#" + zenith + " LO#" + azimuth + " LE#" + length + " NRG#" +
energy + " TIM#" + time + "]";
}
}