/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.das2.qds; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.das2.datum.InconvertibleUnitsException; import org.das2.datum.LoggerManager; import org.das2.datum.Units; import org.das2.datum.UnitsConverter; import org.das2.util.monitor.ProgressMonitor; import org.das2.qds.ops.Ops; /** * DataSetIterator implementation that can be used for all dataset (not just qubes). * Originally this only worked for QDataSets that were qubes, or datasets that * had the same dataset geometry for each slice. At some point this was * modified to work with any dataset but the name remains. * * DataSetIterators are intended to work with multiple datasets at once. For example, * if we want to add the data from two datasets together, we would create one * iterator that would be used to access both datasets. One dataset is provided * to the constructor, but any dataset of the same geometry can be passed to the * getValue method. * * TODO: This does not work for Rank 0 datasets. See * sftp://klunk.physics.uiowa.edu/home/jbf/project/autoplot/script/demos/jeremy/qubeDataSetIteratorForNonQubes.jy * * @author jbf */ public final class QubeDataSetIterator implements DataSetIterator { private static final Logger logger= LoggerManager.getLogger("qdataset.iterator"); /** * DimensionIterator iterates over an index. For example, using * Jython for brevity: *
{@code
* ds= zeros(15,4,2)
* ds[:,:,:] has itertors that count of 0,...,14; 0,...,3; and 0,1
* ds[3:15,:,:] uses a StartStopStepIterator to count off 3,4,5,...,14
* ds[3,:,:] uses a SingletonIterator
* i1= [0,1,2,3]
* i2= [0,0,1,1]
* i3= [0,1,0,1]
* ds[i1,i2,i3] # uses IndexListIterator
*}
* When index is called before hasNext, it must return -1 to indicate an uninitialized state.
*/
public interface DimensionIterator {
/**
* true if there are more indices in the iteration
* @return true if there are more indices in the iteration
*/
boolean hasNext();
/**
* return the next index of the iteration
* @return the next index of the iteration
*/
int nextIndex();
/**
* return the current index.
* @return the current index.
*/
int index();
/**
* return the length of the iteration.
* @return the length of the iteration.
*/
int length();
}
/**
* DimensionIteratorFactory creates DimensionIterators
*/
public interface DimensionIteratorFactory {
DimensionIterator newIterator(int len);
}
/**
* Iterator for counting off indices. (3:15:2 in ds[3:15:2,:])
*/
public static class StartStopStepIterator implements DimensionIterator {
int start;
int stop;
int step;
int index;
boolean all; // just for toString
public StartStopStepIterator(int start, int stop, int step, boolean all) {
this.start = start;
this.stop = stop;
this.step = step;
this.index = start - step;
this.all = all;
}
@Override
public boolean hasNext() {
if ( step>=0 ) {
return index + step < stop;
} else {
return index + step > stop;
}
}
@Override
public int nextIndex() {
index += step;
return index;
}
@Override
public int index() {
return index;
}
@Override
public int length() {
int remainder= (stop - start) % step;
return (stop - start) / step + ( remainder>0 ? 1 :0 );
}
@Override
public String toString() {
return all ? ":" : "" + start + ":" + stop + (step == 1 ? "" : ":" + step);
}
}
/**
* generates iterator for counting off indices. (3:15:2 in ds[3:15:2,:])
* Indices can be negative.
*/
public static class StartStopStepIteratorFactory implements DimensionIteratorFactory {
Number start;
Number stop;
Number step;
/**
* create the factory which will create iterators.
* @param start the start index. negative indices are supported.
* @param stop the stop index, exclusive. null (or None) is used to indicate the end of non-qube datasets.
* @param step the step size, null means just use 1.
*/
public StartStopStepIteratorFactory(Number start, Number stop, Number step) {
this.start = start;
this.stop = stop;
this.step = step;
}
@Override
public DimensionIterator newIterator(int length) {
int step1 = step == null ? 1 : step.intValue();
int dftStart,dftStop;
if ( step1>=0 ) {
dftStart= 0;
dftStop= length;
} else {
dftStart= -1;
dftStop= -1-length; // note danger code which assumes this will still be negative below.
}
int start1 = start == null ? dftStart : start.intValue();
int stop1 = stop == null ? dftStop : stop.intValue();
if (start1 < 0) {
start1 = length + start1;
}
if (stop1 < 0) {
stop1 = length + stop1;
}
return new StartStopStepIterator(start1, stop1, step1, start == null && stop == null && step == null);
}
}
/**
* Iterator that goes through a list of indices.
*/
public static class IndexListIterator implements DimensionIterator {
QDataSet ds;
int listIndex;
public IndexListIterator(QDataSet ds) {
if ( ds.rank()==0 ) {
ds= Ops.join(null,ds);
}
this.ds = ds;
if ( ds.rank()!=1 ) {
throw new IllegalArgumentException("list of indices dataset must be rank 1");
}
this.listIndex = -1;
}
@Override
public boolean hasNext() {
return listIndex+1 < ds.length();
}
@Override
public int nextIndex() {
listIndex++;
return (int) ds.value(listIndex);
}
@Override
public int index() {
return (int) ds.value(listIndex);
}
@Override
public int length() {
return ds.length();
}
@Override
public String toString() {
String dstr= ds.toString();
dstr= dstr.replace("(dimensionless)", "");
return "[" + dstr + " @ " +listIndex + "]";
}
}
/**
* return the current line in the Jython script as <filename>:<linenum>
* or ??? if this cannot be done. Note calls to this will collect a stack
* trace and will affect performance.
* @return the current line or ???
* @see JythonOps#currentLine()
*/
public static String currentJythonLine() {
StackTraceElement[] sts= new Exception().getStackTrace();
int i= 0;
while ( i