package org.das2.dataset; //import java.io.File; //import java.io.IOException; import java.util.WeakHashMap; import org.das2.datum.Units; import org.das2.datum.UnitsUtil; import org.das2.DasException; import org.das2.system.DasLogger; import java.util.logging.*; import org.das2.datum.Datum; import org.das2.datum.DatumRange; import org.das2.datum.DatumRangeUtil; import org.das2.datum.UnitsConverter; import org.das2.qds.DataSetUtil; import org.das2.qds.DDataSet; import org.das2.qds.DataSetOps; import org.das2.qds.JoinDataSet; import org.das2.qds.MutablePropertyDataSet; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; import org.das2.qds.ops.Ops; //import org.das2.qds.util.AsciiFormatter; /** * DataSetRebinner for explicitly doing NN rebinning. The AverageTableRebinner had been used for the purpose, and * there were numerous problems. Also, this looks for BIN_PLUS, BIN_MINUS, BIN_MAX, and BIN_MIN properties in the dataset. */ public class LanlNNRebinner implements DataSetRebinner { private static final Logger logger = DasLogger.getLogger(DasLogger.DATA_OPERATIONS_LOG); public LanlNNRebinner() { } WeakHashMap yds0c= new WeakHashMap(); WeakHashMap yds1c= new WeakHashMap(); WeakHashMap cadence= new WeakHashMap(); WeakHashMap xds0c= new WeakHashMap<>(); /** * get cadence that checks for null and returns the pixel cadence in this case. * @param ds the xtags or ytags * @param res fall-back cadence, that is the axis resolution * @return the rank0 cadence, as linear in the units, or ratiometric log10ratio. */ private QDataSet getCadence( QDataSet ds, Datum res ) { QDataSet dds= cadence.get(ds); if ( dds==null ) { //&& !cadence.containsKey(ds) ) { dds= DataSetUtil.guessCadenceNew( ds, null ); if ( dds==null ) dds= DataSetUtil.asDataSet(res); if ( UnitsUtil.isRatiometric( SemanticOps.getUnits(dds) ) ) { dds= Ops.convertUnitsTo( dds, Units.log10Ratio ); } cadence.put( ds,dds ); } return dds; } /** * rebin the data, using the interpolate control to define the interpolation between measurements. Data that fall into the * same pixel are always averaged in the linear space, regardless of interpolation method. * @param ds rank 2 table or rank 3 join of tables. * @param ddX * @param ddY * @param ddZ * @return * @throws IllegalArgumentException * @throws DasException */ @Override public QDataSet rebin( QDataSet ds, RebinDescriptor ddX, RebinDescriptor ddY, RebinDescriptor ddZ ) throws IllegalArgumentException, DasException { logger.entering("org.das2.dataset.LanlNNRebinner", "rebin"); ddX.setOutOfBoundsAction( RebinDescriptor.EXTRAPOLATE ); ddY.setOutOfBoundsAction( RebinDescriptor.EXTRAPOLATE ); if (ds == null) { throw new NullPointerException("null data set"); } if (!( SemanticOps.isTableDataSet(ds) || SemanticOps.isBundle(ds) ) ) { throw new IllegalArgumentException("Data set must be an instanceof TableDataSet: " + ds.getClass().getName()); } QDataSet tds = (QDataSet) ds; int rank= tds.rank(); if ( rank==2 ) { // make it into a rank 3 table so we are always working with the same scheme. JoinDataSet tdsx= new JoinDataSet(3); tdsx.join(tds); tds= tdsx; } int nx = ddX.numberOfBins(); int ny = ddY.numberOfBins(); DDataSet S= DDataSet.createRank2( nx, ny ); DDataSet N= DDataSet.createRank2( nx, ny ); boolean rs= false; boolean re= false; for ( int itable=0; itable 0 ) { UnitsConverter xc= xunits.getConverter(ddX.getUnits()); QDataSet bounds= SemanticOps.bounds(xds); double start = xc.convert( bounds.value(1,0) ); double end = xc.convert( bounds.value(1,1) ); DatumRange dr= DatumRangeUtil.union( ddX.binStop(ddX.numberOfBins()-1),ddX.binStart(0)); if (start <= dr.max().doubleValue(ddX.getUnits()) ) { rs= true; } if (end >= dr.min().doubleValue(ddX.getUnits())) { re= true; } } logger.log(Level.FINEST, "Allocating rebinData and rebinWeights: {0} x {1}", new Object[]{nx, ny}); double y0,y1; int nYData= rank2y ? yds0.length(0) : yds0.length(); if ( SemanticOps.isBundle(tds1) && tds1.length(0)==3 && !rank2y && yds0.length()==tds1.length() && xds0.length()==tds1.length() ) { // bug 1160: I think some data could still be mistaken here. tds1= DataSetOps.unbundle(tds1,tds1.length(0)-1); weights= DataSetOps.unbundle(weights,weights.length(0)-1); for ( int i=0; iddX.end ) { // flipped px0= ddX.whichBin( x1, xunits ); px1= ddX.whichBin( x0, xunits ); } else { px0= ddX.whichBin( x0, xunits ); px1= ddX.whichBin( x1, xunits ); } double wx= 1./((px1-px0+1)); int sx0= Math.max( 0, px0 ); int sx1= Math.min( nx-1, px1 ); double z= tds1.value( i ); y0= yds0.value(i); y1= yds1.value(i); int py0,py1; if ( ddY.start>ddY.end ) { // flipped py0= ddY.whichBin( y1, yunits ); py1= ddY.whichBin( y0, yunits ); } else { py0= ddY.whichBin( y0, yunits ); py1= ddY.whichBin( y1, yunits ); } double wy= 1./((py1-py0+1)); // favor short bins double w= wx*wy*weights.value(i); int sy0= Math.max( 0, py0 ); int sy1= Math.min( ny-1, py1 ); for ( int k=sx0; k<=sx1; k++ ) { for ( int l=sy0; l<=sy1; l++ ) { if ( w>N.value(k,l) ) { S.putValue(k,l,z*w); N.putValue(k,l,w); } } } } } else { QDataSet yds0_1=null; QDataSet yds1_1=null; if ( rank2y==false ) { yds0_1= yds0; yds1_1= yds1; } int[] py0s= new int[nYData]; int[] py1s= new int[nYData]; double[] wys= new double[nYData]; for ( int i=0; iddX.end ) { // flipped px0= ddX.whichBin( x1, xunits ); px1= ddX.whichBin( x0, xunits ); } else { px0= ddX.whichBin( x0, xunits ); px1= ddX.whichBin( x1, xunits ); } double wx= 1./((px1-px0+1)); int sx0= Math.max( 0, px0 ); int sx1= Math.min( nx-1, px1 ); if ( rank2y ) { yds0_1= yds0.slice(i); yds1_1= yds1.slice(i); } assert yds0_1!=null; assert yds1_1!=null; for ( int j=0; jddY.end ) { // flipped py0= ddY.whichBin( y1, yunits ); py1= ddY.whichBin( y0, yunits ); } else { py0= ddY.whichBin( y0, yunits ); py1= ddY.whichBin( y1, yunits ); } py0s[j]= py0; py1s[j]= py1; double wy= 1./((py1-py0+1)); // favor short bins wys[j]= wy; } } for ( int j=0; jN.value(k,l) ) { S.putValue(k,l,z*w*1.1); N.putValue(k,l,w*1.1); } } } } } } } if ( !rs ) throw new NoDataInIntervalException("data starts after range"); if ( !re ) throw new NoDataInIntervalException("data ends before range"); MutablePropertyDataSet mds= (MutablePropertyDataSet) Ops.divide( S, N ); RebinDescriptor.putDepDataSet( ds, mds, ddX, ddY ); // try { // //System.err.println( String.format( "%d,%d,%f", 40,48, mds.value(40,48) ) ); // new AsciiFormatter().formatToFile( new File( "/tmp/ap.txt"), N ); // } catch (IOException ex) { // Logger.getLogger(LanlNNRebinner.class.getName()).log(Level.SEVERE, null, ex); // } // logger.exiting("org.das2.dataset.LanlNNRebinner", "rebin"); return mds; } private final java.beans.PropertyChangeSupport propertyChangeSupport = new java.beans.PropertyChangeSupport(this); public void addPropertyChangeListener(java.beans.PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(java.beans.PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } }