/* * 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: *
* 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{@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 *}