Skip to content

Commit 9f4296b

Browse files
committed
Firefly-1960: Hips Extraction
- add cube (drill), line, and point extract - add cube extract - added PlotViewUtil.js and some ExtracxtionUIUtil.js test - fixed a bug in rotation checks
1 parent 07e8e69 commit 9f4296b

31 files changed

Lines changed: 2560 additions & 266 deletions

‎src/firefly/java/edu/caltech/ipac/firefly/data/ServerParams.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ public class ServerParams {
3434
public static final String PTARY = "ptAry";
3535
public static final String WPT_ARY = "wptAry";
3636
public static final String WL_ARY = "wlAry";
37-
public static final String FLUX_UNIT= "fluxUnit";
3837
public static final String WL_UNIT= "wlUnit";
3938
public static final String PLANE = "plane";
4039
public static final String CRO_MULTI_ALL = "cropMultiAll";
@@ -100,6 +99,7 @@ public class ServerParams {
10099
public static final String ALL = "all";
101100
public static final String CDS = "cds";
102101
public static final String IS_HIPS_TILE = "isHipsTile";
102+
public static final String HIPS_TILE_URL_ARY = "hipsTileUrlAry";
103103
public static final String HIPS_SOURCES = "hipsSources";
104104
public static final String HIPS_LIST_SOURCE= "hipsListSource";
105105
public static final String HIPS_LIST_SOURCE_NAME= "hipsListSourceName";

‎src/firefly/java/edu/caltech/ipac/firefly/data/table/MetaConst.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ public class MetaConst {
8888
*/
8989
public static final String FITS_FILE_PATH= "FitsFilePath";
9090

91+
/**
92+
* HiPS FITS tile url, the url of the HiPS FITS tile that is associated with this table.
93+
* It is used in extraction from a HiPS. The HiPS root of the url will match the hipsUrlRoot of a HiPS WebPlot
94+
*/
95+
public static final String HIPS_TILE_URL= "HiPSTileUrl";
96+
9197
/**
9298
* Fits Image HDU, The HDU number of a FITS file that is associated with this table
9399
*/

‎src/firefly/java/edu/caltech/ipac/firefly/server/query/ExtractFromImage.java‎

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,25 @@
22

33
import edu.caltech.ipac.firefly.data.ServerParams;
44
import edu.caltech.ipac.firefly.data.TableServerRequest;
5+
import edu.caltech.ipac.firefly.data.table.MetaConst;
6+
import edu.caltech.ipac.firefly.server.ServerContext;
57
import edu.caltech.ipac.firefly.server.SrvParam;
8+
import edu.caltech.ipac.firefly.server.servlets.HiPSRetrieve;
69
import edu.caltech.ipac.table.DataGroup;
710
import edu.caltech.ipac.table.io.FITSExtractToTable;
811
import edu.caltech.ipac.visualize.plot.ImagePt;
912
import edu.caltech.ipac.visualize.plot.WorldPt;
1013
import edu.caltech.ipac.visualize.plot.plotdata.FitsExtract;
1114
import nom.tam.fits.FitsException;
1215

16+
import java.io.File;
1317
import java.io.IOException;
1418
import java.util.ArrayList;
1519
import java.util.HashMap;
1620
import java.util.List;
1721
import java.util.Map;
1822

19-
import static edu.caltech.ipac.firefly.core.Util.Try;
20-
21-
;
23+
import static edu.caltech.ipac.util.StringUtils.isEmpty;
2224

2325
/**
2426
* Extract data from an image and make a table
@@ -32,8 +34,9 @@
3234
@ParamDoc(name="wptAry", desc="for point selection, added to the created table"),
3335
@ParamDoc(name="wlAry[i]", desc="an array of wavelength to add to the table, added to the created table"),
3436
@ParamDoc(name="wlUnit[i]", desc="wavelength units. if defined"),
35-
@ParamDoc(name="fluxUnit[i]", desc="flux units. if defined"),
3637
@ParamDoc(name="filename[i]", desc="filename on the server"),
38+
@ParamDoc(name="hipsTileUrl", desc="z-axis only, url of a HiPS FITS cube tile, used instead of filename"),
39+
@ParamDoc(name=ServerParams.HIPS_TILE_URL_ARY, desc="points or line, url of the HiPS FITS tile of each point, used with ptAry, wptAry and plane instead of the indexed parameters"),
3740
@ParamDoc(name="refHDUNum[i]", desc="hdu number to extract"),
3841
@ParamDoc(name="extractionSizeX", desc="number of the x size of the extract"),
3942
@ParamDoc(name="extractionSizeY", desc="number of the y size of the extract"),
@@ -46,6 +49,7 @@ public class ExtractFromImage extends EmbeddedDbProcessor {
4649
public static final String ID = "ExtractFromImage";
4750
public static final String EXTRACTION_TYPE = "extractionType";
4851
public static final String FILENAME = "filename";
52+
public static final String HIPS_TILE_URL = "hipsTileUrl";
4953
public static final String REF_HDU_NUM = "refHDUNum";
5054
public static final String EXTRACTION_SIZE_X = "extractionSizeX";
5155
public static final String EXTRACTION_SIZE_Y = "extractionSizeY";
@@ -54,44 +58,77 @@ public class ExtractFromImage extends EmbeddedDbProcessor {
5458
@Override
5559
public DataGroup fetchDataGroup(TableServerRequest req) throws DataAccessException {
5660

57-
String extType = req.getParam(EXTRACTION_TYPE);
61+
String extType = req.getParam(EXTRACTION_TYPE, "");
5862
int ptSizeX = req.getIntParam(EXTRACTION_SIZE_X, 1);
5963
int ptSizeY = req.getIntParam(EXTRACTION_SIZE_Y, 1);
6064
FitsExtract.CombineType ct= Enum.valueOf(FitsExtract.CombineType.class,req.getParam(ServerParams.COMBINE_OP,"AVG"));
6165
FitsExtract.SecondaryHduCombine secondCombine= Enum.valueOf(FitsExtract.SecondaryHduCombine.class,req.getParam("secondaryCombine","AUTO"));
6266
boolean allMatchingHDUs = req.getBooleanParam(ALL_MATCHING_HDUS, true);
67+
var isLine= extType.equals("line");
68+
var ptOrLine= extType.equals("points") || isLine;
69+
var hipsTiles= req.getParam(ServerParams.HIPS_TILE_URL_ARY)!=null;
70+
WorldPt[] wptAry = ptOrLine ? SrvParam.getWorldPtAryFromJson(req.getParam(ServerParams.WPT_ARY)) : null;
6371
try {
64-
if (extType == null || extType.equals("z-axis")) {
65-
String filename = req.getParam(FILENAME);
66-
int refHduNum = req.getIntParam(REF_HDU_NUM, -1);
72+
if (extType.equals("z-axis") || isEmpty(extType)) {
73+
String hipsTileUrl = req.getParam(HIPS_TILE_URL);
74+
File fitsFile = hipsTileUrl!=null
75+
? HiPSRetrieve.getHiPSFitsTileFile(hipsTileUrl)
76+
: ServerContext.convertToFile(req.getParam(FILENAME));
77+
int refHduNum = hipsTileUrl!=null ? FitsExtract.FIRST_IMAGE_HDU : req.getIntParam(REF_HDU_NUM, FitsExtract.NOT_SPECIFIED);
6778
ImagePt pt = ImagePt.parse(req.getParam(ServerParams.PT));
6879
WorldPt wpt = WorldPt.parse(req.getParam(ServerParams.WPT));
6980
String wlUnit= req.getParam(ServerParams.WL_UNIT);
7081
double[] wlAry= SrvParam.getDoubleAryFromJson(req.getParam(ServerParams.WL_ARY));
71-
checkZAxisParams(pt, filename, refHduNum);
72-
Map<Integer,String> fluxUnit= makeMapOfUnitsFromParam(req);
73-
return FITSExtractToTable.getCubeZaxisAsTable(pt, wpt, filename, refHduNum, allMatchingHDUs,
74-
ptSizeX, ct, secondCombine, wlAry,wlUnit,fluxUnit);
82+
checkZAxisParams(pt, fitsFile, refHduNum);
83+
DataGroup dg= FITSExtractToTable.getCubeZaxisAsTable(pt, wpt, fitsFile, refHduNum, allMatchingHDUs,
84+
ptSizeX, ct, secondCombine, wlAry,wlUnit);
85+
if (hipsTileUrl!=null) dg.getTableMeta().addKeyword(MetaConst.HIPS_TILE_URL, hipsTileUrl);
86+
return dg;
87+
}
88+
else if (ptOrLine && hipsTiles) {
89+
String[] tileUrlAry= SrvParam.getStringAryFromJson(req.getParam(ServerParams.HIPS_TILE_URL_ARY));
90+
return FITSExtractToTable.getHiPSPointsAsTable(
91+
tileUrlAry,
92+
getHiPSTileFiles(tileUrlAry),
93+
SrvParam.getImagePtAryFromJson(req.getParam(ServerParams.PTARY)),
94+
wptAry,
95+
FitsExtract.FIRST_IMAGE_HDU,
96+
req.getIntParam(ServerParams.PLANE, 0),
97+
allMatchingHDUs, ptSizeX, ptSizeY, ct, secondCombine, isLine);
7598
}
76-
else if (extType.equals("line") || extType.equals("points")) {
99+
else if (ptOrLine) {
77100
var extractParamsList = getDataExtractParams(req);
78-
WorldPt[] wptAry = SrvParam.getWorldPtAryFromJson(req.getParam(ServerParams.WPT_ARY));
79-
return FITSExtractToTable.getDataSelectAsTable(extractParamsList, wptAry, allMatchingHDUs,
80-
ptSizeX, ptSizeY, ct, secondCombine, extType.equals("line"));
101+
return FITSExtractToTable.getDataSelectAsTable(extractParamsList, wptAry,
102+
allMatchingHDUs, ptSizeX, ptSizeY, ct, secondCombine, isLine);
81103
}
82104
} catch (IOException | FitsException e) {
83105
throw new IllegalArgumentException("Could not make a table from extracted data");
84106
}
85107
throw new IllegalArgumentException("extractionType must be z-axis, line, or points");
86108
}
87109

110+
/**
111+
* retrieve the HiPS FITS tiles, each url is retrieved once
112+
* @param tileUrlAry the url of the tile for each point
113+
* @return the file for each url, null for a tile that could not be retrieved
114+
*/
115+
private static File[] getHiPSTileFiles(String[] tileUrlAry) {
116+
if (tileUrlAry==null) throw new IllegalArgumentException(ServerParams.HIPS_TILE_URL_ARY+" is required");
117+
Map<String,File> fileByUrl= new HashMap<>();
118+
File[] fileAry= new File[tileUrlAry.length];
119+
for(int i=0; i<tileUrlAry.length; i++) {
120+
fileAry[i]= fileByUrl.computeIfAbsent(tileUrlAry[i], HiPSRetrieve::getHiPSFitsTileFile);
121+
}
122+
return fileAry;
123+
}
124+
88125
private static List<FITSExtractToTable.DataExtractParams> getDataExtractParams(TableServerRequest req) {
89126
var eList = new ArrayList<FITSExtractToTable.DataExtractParams>();
90127
String[] titles= SrvParam.getStringAryFromJson( req.getParam("titleAry"));
91128
if (titles==null) titles= new String[] {""};
92129
for (int i=0; i<titles.length; i++) {
93130
String filename = req.getParam(FILENAME+i);
94-
int refHduNum = req.getIntParam(REF_HDU_NUM+i, -1);
131+
int refHduNum = req.getIntParam(REF_HDU_NUM+i, FitsExtract.NOT_SPECIFIED);
95132
int plane = req.getIntParam(ServerParams.PLANE+i, -1);
96133
double[] wlAry= SrvParam.getDoubleAryFromJson(req.getParam(ServerParams.WL_ARY+i));
97134
String wlUnit= req.getParam(ServerParams.WL_UNIT+i);
@@ -102,30 +139,21 @@ private static List<FITSExtractToTable.DataExtractParams> getDataExtractParams(T
102139
return eList;
103140
}
104141

105-
private static Map<Integer,String> makeMapOfUnitsFromParam(TableServerRequest req) {
106-
String[] sAry= SrvParam.getStringAryFromJson(req.getParam(ServerParams.FLUX_UNIT));
107-
Map<Integer,String> fluxUnit= new HashMap<>();
108-
if (sAry==null) return fluxUnit;
109-
for(String entry : sAry) {
110-
String[] s= entry.split("=");
111-
if (s.length==2) {
112-
Try.it(() -> fluxUnit.put(Integer.parseInt(s[0]),s[1]));
113-
}
114-
}
115-
return fluxUnit;
116-
}
117-
118-
private static void checkZAxisParams(ImagePt pt, String filename, int refHduNum) {
142+
private static void checkZAxisParams(ImagePt pt, File fitsFile, int refHduNum) {
119143
if (pt==null) throw new IllegalArgumentException("Point is require for z-axis extraction");
120-
if (filename==null) throw new IllegalArgumentException("filename is require for z-axis extraction");
121-
if (refHduNum<0) throw new IllegalArgumentException("refHduNum is require for z-axis extraction");
144+
if (fitsFile==null) throw new IllegalArgumentException("filename or a retrievable hipsTileUrl is require for z-axis extraction");
145+
if (refHduNum==FitsExtract.NOT_SPECIFIED || (refHduNum<0 && refHduNum!=FitsExtract.FIRST_IMAGE_HDU)) {
146+
throw new IllegalArgumentException("refHduNum is require for z-axis extraction");
147+
}
122148
}
123149

124150
private static void checkPointParams(ImagePt[] ptAry, int plane, String filename, int refHduNum) {
125151
if (ptAry==null || ptAry.length==0) throw new IllegalArgumentException("ptAry is require for points extraction");
126152
if (filename==null) throw new IllegalArgumentException("filename is require for points extraction");
127-
if (refHduNum<0) throw new IllegalArgumentException("refHduNum is require for points extraction");
128-
if (plane<0) throw new IllegalArgumentException("refHduNum is require for points extraction");
153+
if (refHduNum==FitsExtract.NOT_SPECIFIED || refHduNum<0) {
154+
throw new IllegalArgumentException("refHduNum is require for points extraction");
155+
}
156+
if (plane<0) throw new IllegalArgumentException("plane is require for points extraction");
129157
}
130158

131159
}

‎src/firefly/java/edu/caltech/ipac/firefly/server/rpc/VisServerCommands.java‎

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import edu.caltech.ipac.firefly.server.ServCommand;
99
import edu.caltech.ipac.firefly.server.ServerCommandAccess;
1010
import edu.caltech.ipac.firefly.server.SrvParam;
11+
import edu.caltech.ipac.firefly.server.servlets.HiPSRetrieve;
1112
import edu.caltech.ipac.firefly.server.util.Logger;
13+
import edu.caltech.ipac.firefly.server.visualize.CtxControl;
1214
import edu.caltech.ipac.firefly.server.visualize.DirectStretchUtils.CompressType;
1315
import edu.caltech.ipac.firefly.server.visualize.FluxValueUtil;
1416
import edu.caltech.ipac.firefly.server.visualize.VisJsonSerializer;
@@ -26,6 +28,7 @@
2628
import org.json.simple.JSONArray;
2729
import org.json.simple.JSONObject;
2830

31+
import java.io.File;
2932
import java.io.IOException;
3033
import java.nio.ByteBuffer;
3134
import java.nio.ByteOrder;
@@ -201,30 +204,36 @@ private static CompressType getCompressType(SrvParam sp) {
201204
public static class ExtractionCmd extends ServerCommandAccess.HttpCommand {
202205
public void processRequest(HttpServletRequest req, HttpServletResponse res, SrvParam sp) throws Exception {
203206

204-
PlotState state= sp.getState();
207+
boolean isHiPSTile= sp.getOptionalBoolean(ServerParams.IS_HIPS_TILE, false);
205208
String exType= sp.getRequired(ServerParams.EXTRACTION_TYPE);
206209
boolean useFloat = sp.getOptionalInt(ServerParams.EXTRACTION_FLOAT_SIZE,64)==32;
207210
int ptSize= sp.getOptionalInt(ServerParams.POINT_SIZE,1);
208211
int ptSizeX= sp.getOptionalInt(ServerParams.POINT_SIZE_X,1);
209212
int ptSizeY= sp.getOptionalInt(ServerParams.POINT_SIZE_Y,1);
210-
int hduNum= sp.getRequiredInt(ServerParams.HDU_NUM);
213+
int hduNum= isHiPSTile ? FitsExtract.FIRST_IMAGE_HDU : sp.getRequiredInt(ServerParams.HDU_NUM);
211214
FitsExtract.CombineType ct= Enum.valueOf(FitsExtract.CombineType.class,sp.getOptional(ServerParams.COMBINE_OP,"AVG"));
212215

213216
List<Number> extractList= switch (exType) {
214217
case "z-axis" ->
215-
VisServerOps.getZAxisAry(state,
218+
VisServerOps.getZAxisAry(getFitsFile(sp,isHiPSTile),
216219
sp.getRequiredImagePt(ServerParams.PT),
217220
hduNum, ptSize, ct);
218221

219222
case "line" ->
220-
VisServerOps.getLineDataAry(state,
223+
VisServerOps.getLineDataAry(getFitsFile(sp,isHiPSTile),
221224
sp.getRequiredImagePt(ServerParams.PT),
222225
sp.getRequiredImagePt(ServerParams.PT2),
223226
sp.getRequiredInt(ServerParams.PLANE),
224227
hduNum, ptSize, ct);
225228

226-
case "points" ->
227-
VisServerOps.getPointDataAry(state,
229+
case "points" -> isHiPSTile
230+
? VisServerOps.getHiPSPointDataAry(
231+
SrvParam.getStringAryFromJson(sp.getRequired(ServerParams.HIPS_TILE_URL_ARY)),
232+
sp.getRequiredImagePtAry(ServerParams.PTARY),
233+
hduNum,
234+
sp.getRequiredInt(ServerParams.PLANE),
235+
ptSizeX, ptSizeY, ct)
236+
: VisServerOps.getPointDataAry(getFitsFile(sp,isHiPSTile),
228237
sp.getRequiredImagePtAry(ServerParams.PTARY),
229238
sp.getRequiredInt(ServerParams.PLANE),
230239
hduNum, ptSizeX, ptSizeY, ct);
@@ -253,6 +262,17 @@ public void processRequest(HttpServletRequest req, HttpServletResponse res, SrvP
253262
}
254263
}
255264

265+
/**
266+
* @param sp the parameters
267+
* @param isHiPSTile if true use the URL parameter of a HiPS FITS tile, otherwise the plot state
268+
* @return the FITS file to extract from or null if it is not available
269+
*/
270+
private static File getFitsFile(SrvParam sp, boolean isHiPSTile) {
271+
return isHiPSTile
272+
? HiPSRetrieve.getHiPSFitsTileFile(sp.getRequired(ServerParams.URL))
273+
: CtxControl.getConfirmedWorkingFitsFile(sp.getState());
274+
}
275+
256276
public static class Crop extends ServCommand {
257277

258278
public String doCommand(SrvParam sp) throws IllegalArgumentException {

‎src/firefly/java/edu/caltech/ipac/firefly/server/servlets/HiPSRetrieve.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,17 @@ private record DeadEntry(long time, int status) {};
6161

6262
public static FileInfo retrieveHiPSData(String urlStr, boolean alwaysUseCached) {
6363
return retrieveHiPSData(urlStr,null, alwaysUseCached);
64+
}
6465

66+
/**
67+
* Get a HiPS FITS tile, retrieving it if it is not in the cache. This call will block on the retrieve.
68+
* @param fitsTileUrl the url of the HiPS FITS tile
69+
* @return the cached FITS file or null if it could not be retrieved
70+
*/
71+
public static File getHiPSFitsTileFile(String fitsTileUrl) {
72+
if (fitsTileUrl==null || isDeadFitsUrl(fitsTileUrl)) return null;
73+
FileInfo fi= retrieveHiPSData(fitsTileUrl, true);
74+
return fi.isSuccess() ? fi.getFile() : null;
6575
}
6676

6777
public static FileInfo retrieveHiPSData(String urlStr, String fileName, boolean alwaysUseCached) {

‎src/firefly/java/edu/caltech/ipac/firefly/server/visualize/CtxControl.java‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,31 @@ public static void confirmFiles(PlotState state) throws FailedRequestException {
3232
if (isFitsFilesMissing(state)) revalidatePlot(state,true); //most of the time the files are there so nothing happens
3333
}
3434

35+
/**
36+
* Get the NO_BAND working FITS file of a standard (non-HiPS) plot
37+
* @param state the plot state
38+
* @return the FITS file or null if it could not be confirmed
39+
*/
40+
public static File getConfirmedWorkingFitsFile(PlotState state) {
41+
return getConfirmedWorkingFitsFile(state,Band.NO_BAND);
42+
}
43+
44+
/**
45+
* Get the working FITS file of a standard (non-HiPS) plot
46+
* @param state the plot state
47+
* @param band the band of the file
48+
* @return the FITS file or null if it could not be confirmed
49+
*/
50+
public static File getConfirmedWorkingFitsFile(PlotState state, Band band) {
51+
try {
52+
confirmFiles(state);
53+
return ServerContext.convertToFile(state.getWorkingFitsFileStr(band));
54+
} catch (FailedRequestException e) {
55+
Logger.getLogger().warn(e, "could not confirm working FITS file: " + e.getMessage());
56+
return null;
57+
}
58+
}
59+
3560
private static boolean isFitsFilesMissing(PlotState state) {
3661
return state.isThreeColor() ?
3762
Arrays.stream(state.getBands())

‎src/firefly/java/edu/caltech/ipac/firefly/server/visualize/FitsCacher.java‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ private static DirectFileAccess makeDirectFileAccessData(FitsRead fr) {
249249
var blankVal= FitsReadUtil.getBlankValue(h);
250250
var blankValStr= Double.isNaN(blankVal) ? "" : blankVal+"";
251251
return new DirectFileAccess(
252-
fr.getHduNumber(), fr.isCube(), FitsReadUtil.getNaxis3(h), -1, dataOffset, h.getIntValue(SPOT_BP),
252+
FitsReadUtil.getExtNameOrType(h),
253+
fr.getHduNumber(), fr.isCube(), FitsReadUtil.getNaxis3(h), FitsReadUtil.getNaxis(h),
254+
dataOffset, h.getIntValue(SPOT_BP),
253255
FitsReadUtil.getNaxis1(h), FitsReadUtil.getNaxis2(h), FitsReadUtil.getNaxis3(h),
254256
FitsReadUtil.getCdelt2(h), FitsReadUtil.getBUnit(h,"---"),
255257
FitsReadUtil.getBscale(h), FitsReadUtil.getBzero(h),

0 commit comments

Comments
 (0)