/* File: RebinDescriptor.java * Copyright (C) 2002-2003 The University of Iowa * Created by: Jeremy Faden * Jessica Swanner * Edward E. West * * This file is part of the das2 library. * * das2 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.das2.dataset; import java.util.logging.Level; import java.util.logging.Logger; import org.das2.datum.DatumVector; import org.das2.datum.UnitsConverter; import org.das2.datum.Datum; import org.das2.datum.LoggerManager; import org.das2.datum.Units; import org.das2.qds.DDataSet; import org.das2.qds.DataSetOps; import org.das2.qds.MutablePropertyDataSet; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; /** * The RebinDescriptor will quickly look up which 1-D bin a Datum is * in. This is not thread-safe, and must be used by only one thread during its * lifetime. * @author jbf */ public final class RebinDescriptor { private static final Logger logger= LoggerManager.getLogger("das2.data.rebinner"); Units units; protected double start; protected double end; protected int nBin; protected boolean isLog = false; public static final int FIRSTORLAST=-2; // return the closest valid bin, first or last public static final int MINUSONE= -3; // return sentinel -1. public static final int EXTRAPOLATE= -4; // return negative or >nBin. private int outOfBoundsAction= EXTRAPOLATE; /** Creates a new instance of RebinDescriptor */ private RebinDescriptor() { } public RebinDescriptor(double start, double end, Units units, int nBin, boolean isLog) { this.units= units; if (isLog) { this.start= Math.log(start); this.end= Math.log(end); } else { this.start= start; this.end= end; } this.nBin= nBin; this.isLog= isLog; } public RebinDescriptor( Datum start, Datum end, int nBin, boolean isLog) { this(start.doubleValue(start.getUnits()),end.doubleValue(end.getUnits()),start.getUnits(),nBin,isLog); if (start.getUnits()!=end.getUnits()) throw new IllegalArgumentException( "start and end units differ: \""+start.getUnits()+ "\" \"" +end.getUnits()+ "\"" ); } public int numberOfBins() { return nBin; } private UnitsConverter uc; // cache UnitsConverter private Units inUnits=null; // cache units. public int whichBin( double x, Units units ) { if ( units!=this.units ) { if ( uc==null || units!=inUnits ) { // small optimization doesn't seem to have a large effect. uc= Units.getConverter(units,this.units); inUnits= units; } x= uc.convert(x); } int result=0; if (isLog) x= Math.log(x); boolean outOfBounds= start < end ? (x=end) : (x=start) ; if ( outOfBounds && outOfBoundsAction!=EXTRAPOLATE) { switch (outOfBoundsAction) { case FIRSTORLAST: result= start < end ? ( x= numberOfBins() ) { throw new IllegalArgumentException("bin "+ibin+" is out of bounds"); } } double result= start+((ibin)/(double)(nBin)*(end-start)); UnitsConverter cu= this.units.getConverter(units); if ( isLog ) { return cu.convert(Math.exp(result)); } else { return cu.convert(result); } } public Datum binStop( int ibin ) { return Datum.create( binStop( ibin, units ), units ); } /** * return the bigger boundary of the bin. * @param ibin the bin number * @param units the units for the result. * @return the bigger boundary of the bin in the desired units. */ public double binStop( int ibin, Units units ) { if ( this.outOfBoundsAction!=RebinDescriptor.EXTRAPOLATE ) { if ( ibin<0 || ibin >= numberOfBins() ) { throw new IllegalArgumentException("bin "+ibin+" is out of bounds"); } } double result= start+((ibin+1)/(double)(nBin)*(end-start)); UnitsConverter cu= this.units.getConverter(units); if ( isLog ) { return cu.convert(Math.exp(result)); } else { return cu.convert(result); } } /** * return the bin starts of all bins, in units of getUnits() * @return the bin starts of all bins */ public double[] binStarts() { double [] result= new double[nBin]; for (int i=0; igetUnits() * @return the bin stops of all bins */ public double[] binStops() { double [] result= new double[nBin]; for (int i=0; i0 ) { i0= 0; ymin= units.createDatum(ddY.binStart(0, units)); } if ( i0< -10000000 ) { throw new IllegalArgumentException( "ymin would result in impossibly large rebin descriptor (ymin="+ymin+" falls in bin number "+i0+")" ); } int i1= dd.whichBin( ymax.doubleValue(units), units ); if ( i1 10000000 ) { throw new IllegalArgumentException( "ymax would result in impossibly large rebin descriptor (ymax="+ymax+" falls in bin number "+i0+")" ); } int nbins= i1-i0+1; return new RebinDescriptor( units.createDatum(dd.binStart(i0,units)), units.createDatum(dd.binStop(i1,units)), nbins, dd.isLog() ); } public double binWidth() { return (end-start)/(double)nBin; } public Datum binWidthDatum() { return Datum.create( binWidth(), getUnits().getOffsetUnits() ); } public boolean isLog() { return isLog; } public Units getUnits() { return units; } /** * taken from AverageTableRebinner * @param ds the original dataset * @param result the rank 2 rebin target. * @param ddX the descriptor, or null. * @param ddY the descriptor, or null. */ public static void putDepDataSet( QDataSet ds, MutablePropertyDataSet result, RebinDescriptor ddX, RebinDescriptor ddY ) { QDataSet xds= SemanticOps.xtagsDataSet(ds); MutablePropertyDataSet xx; if ( ddX!=null ) { DDataSet xxx= DDataSet.createRank1( ddX.numberOfBins() ); for ( int i=0; i