/*
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.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import java.net.URL;

import java.rmi.RemoteException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;

import visad.Data;
import visad.FieldImpl;
import visad.FlatField;
import visad.FunctionType;
import visad.Integer1DSet;
import visad.RealType;
import visad.RealTupleType;
import visad.VisADException;

import visad.data.BadFormException;

class DoubleCache
{
  private double value;

  DoubleCache() { this(Double.NaN); }
  DoubleCache(double v) { value = v; }
  double getValue() { return value; }
  void setValue(double v) { value = v; }
}

class FloatCache
{
  private float value;

  FloatCache() { this(Float.NaN); }
  FloatCache(float v) { value = v; }
  float getValue() { return value; }
  void setValue(float v) { value = v; }
}

class IntCache
{
  private int value;

  IntCache() { this(-1); }
  IntCache(int v) { value = v; }
  int getValue() { return value; }
  void setValue(int v) { value = v; }
}

public class AmandaFile
{
  public static final RealType moduleIndexType =
    RealType.getRealType("Module_Index");

  public static RealTupleType xyzType;

  static {
    try {
      xyzType =
        new RealTupleType(RealType.XAxis, RealType.YAxis, RealType.ZAxis);
    } catch (VisADException ve) {
      ve.printStackTrace();
      xyzType = null;
    }
  }

  private double xmin = Double.MAX_VALUE;
  private double xmax = Double.MIN_VALUE;
  private double ymin = Double.MAX_VALUE;
  private double ymax = Double.MIN_VALUE;
  private double zmin = Double.MAX_VALUE;
  private double zmax = Double.MIN_VALUE;

  private ModuleList modules = new ModuleList();
  private ArrayList events = new ArrayList();

  private HashMap lastCache = new HashMap();

  public AmandaFile(String id)
    throws BadFormException, IOException, VisADException
  {
    FileReader rdr = new FileReader(id);
    try {
      loadFile(new BufferedReader(rdr));
    } finally {
      try { rdr.close(); } catch (IOException ioe) { }
    }
  }

  public AmandaFile(URL url)
    throws BadFormException, IOException, VisADException
  {
    InputStream is = url.openStream();
    try {
      loadFile(new BufferedReader(new InputStreamReader(is)));
    } finally {
      try { is.close(); } catch (IOException ioe) { }
    }
  }

  private void loadFile(BufferedReader br)
    throws BadFormException, VisADException
  {
    // read V record
    String firstLine;
    try {
      firstLine = nextLine(br);
    } catch (IOException ioe) {
      throw new BadFormException("Unreadable file");
    }

    if (firstLine == null || firstLine.length() <= 1 ||
        firstLine.charAt(0) != 'v' ||
        !Character.isSpaceChar(firstLine.charAt(1)))
    {
      throw new BadFormException("Bad first line \"" + firstLine + "\"");
    }

    Event currentEvent = null;
    boolean inSlowEvent = false;

    while (true) {
      String line;
      try {
        line = nextLine(br);
      } catch (IOException ioe) {
        throw new BadFormException("Unreadable file");
      }

      // end loop if we've reached the end of the file
      if (line == null) {
        break;
      }

      // ignore blank lines
      if (line.length() == 0) {
        continue;
      }

      StringTokenizer tok = new StringTokenizer(line);

      String keyword = tok.nextToken();

      if (keyword.equals("array")) {
        if (modules.isInitialized()) {
          System.err.println("Warning: Multiple ARRAY lines found");
        }

        int nmodules = readArrayLine(line, tok);

        continue;
      }

      if (keyword.equals("om")) {
        Module module = readOMLine(line, tok);
        if (module != null) {
          modules.add(module);

          final float x = module.getX();
          if (x == x) {
            if (x < xmin) xmin = x;
            if (x > xmax) xmax = x;
          }
          final float y = module.getY();
          if (y == y) {
            if (y < ymin) ymin = y;
            if (y > ymax) ymax = y;
          }
          final float z = module.getZ();
          if (z == z) {
            if (z < zmin) zmin = z;
            if (z > zmax) zmax = x;
          }
        }

        continue;
      }

      if (keyword.equals("es")) {
        // ignore ES events for now
        if (inSlowEvent) {
          System.err.println("Warning: Missing EE for slow event");
        }

        inSlowEvent = true;

        continue;
      }

      if (keyword.equals("em")) {
        if (currentEvent != null) {
          System.err.println("Warning: Missing EE for " + currentEvent);
        }

        currentEvent = startEvent(line, tok);

        continue;
      }

      // read TR and HT records
      if (keyword.equals("tr")) {
        MCTrack track = readTrack(line, tok);
        if (track != null) {
          if (currentEvent == null) {
            System.err.println("Found TRACK " + track +
                               " outside event");
          } else {
            currentEvent.add(track);
          }
        }

        continue;
      }

      if (keyword.equals("fit")) {
        FitTrack fit = readFit(line, tok);
        if (fit != null) {
          if (currentEvent == null) {
            System.err.println("Found FIT " + fit +
                               " outside event");
          } else {
            currentEvent.add(fit);
          }
        }

        continue;
      }

      if (keyword.equals("ht")) {
        Hit hit = readHit(line, tok);
        if (hit != null) {
          if (currentEvent == null) {
            System.err.println("Found HIT " + hit +
                               " outside event");
          } else {
            currentEvent.add(hit);
          }
        }

        continue;
      }

      if (keyword.equals("ee")) {
        if (currentEvent == null) {
          if (inSlowEvent) {
            inSlowEvent = false;
          } else {
            System.err.println("Found EE outside event");
          }
        } else {
          events.add(currentEvent);
          currentEvent = null;
        }

        continue;
      }
    }

    // remove cached values since they're no longer needed
    lastCache.clear();
  }

  private final void dump(java.io.PrintStream out)
  {
    final int nEvents = events.size();
    for (int i = 0; i < nEvents; i++) {
      ((Event )events.get(i)).dump(out);
    }

    modules.dump(out);
  }

  public final Event getEvent(int index)
  {
    return (Event )events.get(index);
  }

  public final int getNumberOfEvents() { return events.size(); }

  public final double getXMax() { return xmax; }
  public final double getXMin() { return xmin; }

  public final double getYMax() { return ymax; }
  public final double getYMin() { return ymin; }

  public final double getZMax() { return zmax; }
  public final double getZMin() { return zmin; }

  public final FieldImpl makeEventData()
  {
    final int num = events.size();
    Integer1DSet set;
    try {
      set = new Integer1DSet(Event.indexType, (num == 0 ? 1 : num));
    } catch (VisADException ve) {
      ve.printStackTrace();
      return null;
    }

    FunctionType funcType;
    FieldImpl fld;
    try {
      funcType = new FunctionType(Event.indexType, Hits.timeSequenceType);
      fld = new FieldImpl(funcType, set);
    } catch (VisADException ve) {
      ve.printStackTrace();
      return null;
    }

    if (num > 0) {
      Data[] samples = new Data[num];
      for (int e = 0; e < num; e++) {
        samples[e] = ((Event )events.get(e)).makeHitSequence();
      }
      try {
        fld.setSamples(samples, false);
      } catch (RemoteException re) {
        re.printStackTrace();
      } catch (VisADException ve) {
        ve.printStackTrace();
      }
    }

    return fld;
  }

  public final FlatField makeModuleData()
    throws RemoteException, VisADException
  {
    // Field of modules
    final int num = modules.size();
    Integer1DSet set;
    try {
      set = new Integer1DSet(moduleIndexType, num);
    } catch (VisADException ve) {
      ve.printStackTrace();
      return null;
    }

    FunctionType funcType;
    FlatField fld;
    try {
      funcType = new FunctionType(moduleIndexType, xyzType);
      fld = new FlatField(funcType, set);
    } catch (VisADException ve) {
      ve.printStackTrace();
      return null;
    }

    if (num > 0) {
      float[][] samples = new float[3][num];
      for (int i = 0; i < num; i++) {
        Module mod = modules.get(i);
        samples[0][i] = mod.getX();
        samples[1][i] = mod.getY();
        samples[2][i] = mod.getZ();
      }
      try {
        fld.setSamples(samples);
      } catch (RemoteException re) {
        re.printStackTrace();
      }
    }

    return fld;
  }

  private String nextLine(BufferedReader rdr)
    throws IOException
  {
    String line = rdr.readLine();
    if (line != null) {
      line = line.trim().toLowerCase();
    }

    return line;
  }

  private int parseChannel(String tokenName, String token)
    throws NumberFormatException
  {
    final int dotIdx = token.indexOf('.');
    if (dotIdx >= 0) {
      token = "-" + token.substring(dotIdx + 1);
    }

    return parseInt(tokenName, token);
  }

  private double parseDouble(String tokenName, String token)
    throws NumberFormatException
  {
    double value;
    if (token == null) {
      value = Double.NaN;
    } else if (token.equals("inf")) {
      value = Double.POSITIVE_INFINITY;
    } else if (token.equals("-inf")) {
      value = Double.NEGATIVE_INFINITY;
    } else if (token.equals("?")) {
      value = Double.NaN;
    } else if (token.equals("nan")) {
      value = Double.NaN;
    } else if (token.equals("*")) {
      DoubleCache cval = (DoubleCache )lastCache.get(tokenName);
      if (cval == null) {
        value = Double.NaN;
      } else {
        value = cval.getValue();
      }
    } else {
      value = Double.parseDouble(token);
    }

    // save value in case next reference uses '*' to access it
    DoubleCache cache = (DoubleCache )lastCache.get(tokenName);
    if (cache == null) {
      lastCache.put(tokenName, new DoubleCache(value));
    } else {
      cache.setValue(value);
    }

    return value;
  }

  private float parseFloat(String tokenName, String token)
    throws NumberFormatException
  {
    float value;
    if (token == null) {
      value = Float.NaN;
    } else if (token.equals("inf")) {
      value = Float.POSITIVE_INFINITY;
    } else if (token.equals("-inf")) {
      value = Float.NEGATIVE_INFINITY;
    } else if (token.equals("?")) {
      value = Float.NaN;
    } else if (token.equals("nan")) {
      value = Float.NaN;
    } else if (token.equals("*")) {
      FloatCache cval = (FloatCache )lastCache.get(tokenName);
      if (cval == null) {
        value = Float.NaN;
      } else {
        value = cval.getValue();
      }
    } else {
      value = Float.parseFloat(token);
    }

    // save value in case next reference uses '*' to access it
    FloatCache cache = (FloatCache )lastCache.get(tokenName);
    if (cache == null) {
      lastCache.put(tokenName, new FloatCache(value));
    } else {
      cache.setValue(value);
    }

    return value;
  }

  private int parseInt(String tokenName, String token)
    throws NumberFormatException
  {
    int value;
    if (token == null) {
      value = -1;
    } else if (token.equals("inf")) {
      value = Integer.MAX_VALUE;
    } else if (token.equals("-inf")) {
      value = Integer.MIN_VALUE;
    } else if (token.equals("?")) {
      value = -1;
    } else if (token.equals("nan")) {
      value = -1;
    } else if (token.equals("*")) {
      IntCache cval = (IntCache )lastCache.get(tokenName);
      if (cval == null) {
        value = -1;
      } else {
        value = cval.getValue();
      }
    } else {
      value = Integer.parseInt(token);
    }

    // save value in case next reference uses '*' to access it
    IntCache cache = (IntCache )lastCache.get(tokenName);
    if (cache == null) {
      lastCache.put(tokenName, new IntCache(value));
    } else {
      cache.setValue(value);
    }

    return value;
  }

  private int readArrayLine(String line, StringTokenizer tok)
    throws BadFormException
  {
    String detector = tok.nextToken();
    int nstrings, nmodules;
    try {
      float longitude = parseFloat("raLon", tok.nextToken());
      float latitude = parseFloat("raLat", tok.nextToken());
      float depth = parseFloat("raDepth", tok.nextToken());
      nstrings = parseInt("raNStr", tok.nextToken());
      nmodules = parseInt("raNMod", tok.nextToken());
    } catch(NumberFormatException e) {
      throw new BadFormException("Bad ARRAY line \"" + line + "\": " +
                                 e.getMessage());
    }

    if (nstrings < 1 || nmodules < 1) {
      throw new BadFormException("Bad ARRAY line \"" + line + "\": " +
                                 (nstrings < 1 ? "nstrings < 1" :
                                  "nmodule < 1"));
    }

    return nmodules;
  }

  private final FitTrack readFit(String line, StringTokenizer tok)
    throws VisADException
  {
    // FIT id type xstart ystart zstart zenith azimuth time length energy
    float xstart, ystart, zstart, zenith, azimuth, length, energy, time;

    // skip ID field
    tok.nextToken();
    tok.nextToken();

    try {
      xstart = parseFloat("fitXStart", tok.nextToken());
      ystart = parseFloat("fitYStart", tok.nextToken());
      zstart = parseFloat("fitZStart", tok.nextToken());
      zenith = parseFloat("fitZenith", tok.nextToken()); // 0.0f toward -z
      azimuth = parseFloat("fitAzimuth", tok.nextToken()); // 0.0f toward +x
      time = parseFloat("fitTime", tok.nextToken());
      length = parseFloat("fitLength", tok.nextToken());
      energy = parseFloat("fitEnergy", tok.nextToken());
    } catch(NumberFormatException e) {
      throw new BadFormException("Bad FIT line \"" + line + "\": " +
                                 e.getMessage());
    }

    return new FitTrack(xstart, ystart, zstart, zenith, azimuth, length,
                        energy, time);
  }

  private final Hit readHit(String line, StringTokenizer tok)
    throws VisADException
  {
    String chanStr = tok.nextToken();
    int number = parseChannel("htNum", chanStr);
    if (number < 0) {
      System.err.println("Warning: Ignoring HIT for secondary channel \"" +
                         chanStr + "\"");
      return null;
    }

    // find this module
    Module mod = modules.find(number);
    if (mod == null) {
      System.err.println("Warning: Module not found for HIT line \"" +
                         line + "\"; hit ignored");
      return null;
    }

    float amplitude, leadEdgeTime, timeOverThreshold;
    try {
      amplitude = parseFloat("htAmp", tok.nextToken());

      // skip pulse id & parent track
      tok.nextToken();
      tok.nextToken();

      leadEdgeTime = parseFloat("htLet", tok.nextToken());
      timeOverThreshold = parseFloat("htTot", tok.nextToken());

      // ignore number of TDC edges
    } catch(NumberFormatException e) {
      throw new BadFormException("Bad HIT line \"" + line + "\": " +
                                 e.getMessage());
    }

    return new Hit(mod, amplitude, leadEdgeTime, timeOverThreshold);
  }

  private final Module readOMLine(String line, StringTokenizer tok)
    throws BadFormException
  {
    String numStr = tok.nextToken();

    int number;
    try {
      number = parseInt("omNum", numStr);
    } catch(NumberFormatException e) {
      throw new BadFormException("unparseable module number \"" + numStr +
                                 "\" in \"" + line + "\"");
    }

    if (number < 0) {
      throw new BadFormException("bad module number \"" + numStr +
                                 "\" in \"" + line + "\"");
    }

    int stringOrder, string;
    float x, y, z;
    try {
      stringOrder = parseInt("modOrd", tok.nextToken());
      string = parseInt("modStr", tok.nextToken());
      x = parseFloat("modX", tok.nextToken());
      y = parseFloat("modY", tok.nextToken());
      z = parseFloat("modZ", tok.nextToken());
    } catch(NumberFormatException e) {
      throw new BadFormException("Bad OM line \"" + line + "\": " +
                                 e.getMessage());
    }

    return new Module(number, x, y, z, string, stringOrder);
  }

  private final MCTrack readTrack(String line, StringTokenizer tok)
    throws VisADException
  {
    // TR nr parent type xstart ystart zstart zenith azimuth length energy time
    // skip first three fields
    for (int i = 0; i < 3; i++) {
      tok.nextToken();
    }

    float xstart, ystart, zstart, zenith, azimuth, length, energy, time;
    try {
      xstart = parseFloat("trXStart", tok.nextToken());
      ystart = parseFloat("trYStart", tok.nextToken());
      zstart = parseFloat("trZStart", tok.nextToken());
      zenith = parseFloat("trZenith", tok.nextToken()); // 0.0f toward -z
      azimuth = parseFloat("trAzimuth", tok.nextToken()); // 0.0f toward +x
      length = parseFloat("trLength", tok.nextToken());
      energy = parseFloat("trEnergy", tok.nextToken());
      time = parseFloat("trTime", tok.nextToken());
    } catch(NumberFormatException e) {
      throw new BadFormException("bad TRACK line \"" + line + "\": " +
                                 e.getMessage());
    }

    return new MCTrack(xstart, ystart, zstart, zenith, azimuth, length,
                       energy, time);
  }

  private final Event startEvent(String line, StringTokenizer tok)
    throws BadFormException
  {
    // assemble EM event
    int evtNum, runNum, year, day;
    double time, timeShift;
    try {
      evtNum = parseInt("emNum", tok.nextToken());
      runNum = parseInt("emRun", tok.nextToken());
      year = parseInt("emYear", tok.nextToken());
      day = parseInt("emDay", tok.nextToken());
      time = parseDouble("emTime", tok.nextToken());
      if (!tok.hasMoreTokens()) {
        timeShift = Double.NaN;
      } else {
        // time shift in nsec of all times in event
        timeShift = parseDouble("emTimeShift", tok.nextToken()) * 0.000000001;
      }
    } catch(NumberFormatException e) {
      throw new BadFormException("Bad EM line \"" + line + "\": " +
                                 e.getMessage());
    }

    return new Event(evtNum, runNum, year, day, time, timeShift);
  }
}

 

Ads help maintain this website.