diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/IrsaLightCurveHandler.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/IrsaLightCurveHandler.java new file mode 100644 index 0000000000..0b386fe55c --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/IrsaLightCurveHandler.java @@ -0,0 +1,144 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query.lc; + +import edu.caltech.ipac.astro.IpacTableWriter; +import edu.caltech.ipac.firefly.server.ServerContext; +import edu.caltech.ipac.util.DataGroup; +import edu.caltech.ipac.util.VoTableUtil; +import edu.caltech.ipac.util.download.FailedRequestException; +import edu.caltech.ipac.util.download.URLDownload; +import org.apache.commons.lang.NotImplementedException; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + + +/** + * . + * Should handle the LC transformations to get files out of the API result VOtable xml + * + * @author ejoliet + * @see PeriodogramAPIRequest + */ +public class IrsaLightCurveHandler implements LightCurveHandler { + + + /** + * TODO Update with correct API root url + */ + public final String rootApiUrl = "http://irsa.ipac.caltech.edu/periodogram"; + + public File getPeriodogramTable(PeriodogramAPIRequest request) { + + return ipacTableFromAPI(request, RESULT_TABLES_IDX.PERIODOGRAM); + + } + + + /** + * @return peaks table (default: 50 rows) + */ + public File getPeaksTable(PeriodogramAPIRequest request) { + + return ipacTableFromAPI(request, RESULT_TABLES_IDX.PEAKS); + } + + /** + * Return a phase folded curve form original light-curve + * + * @param tbl orginal lc table + * @param period period for phase folding the lc curve + * @return phase folded curve (x2 original input table 0,2 phase) + */ + public File toPhaseFoldedTable(File tbl, float period) { + //get raw lcTable and phase fold on time/period + //for now, return same table. + //TODO change it with the implementation DM-7165 + return tbl; + } + + /** + * Return the API URL to be called to get VOTable from Nexsci, which will contain 2 tables: periodogram and peaks tables. + *

+ * TODO need to be implemented + * + * @param request object to contain the required paramter to make the API call + * @return the URL object + * @throws MalformedURLException + * @see LightCurveProcessor#computePeriodogram(PeriodogramAPIRequest, java.lang.String) + * @see IrsaLightCurveHandler#buildUrl(PeriodogramAPIRequest) + */ + protected URL buildUrl(PeriodogramAPIRequest request) throws MalformedURLException { + //loop other request and append to rootApiUrl + throw new NotImplementedException("Not yet implemented"); + } + + protected File extractTblFrom(File votableResult, RESULT_TABLES_IDX resultTable) { + File resultTblFile = null; + try { + resultTblFile = makeResultTempFile(resultTable); + DataGroup[] dataGroups = VoTableUtil.voToDataGroups(votableResult.getAbsolutePath()); + + IpacTableWriter.save(resultTblFile, dataGroups[resultTable.ordinal()]); + return resultTblFile; + } catch (IOException e) { + e.printStackTrace(); + } + return resultTblFile; + } + + protected File ipacTableFromAPI(PeriodogramAPIRequest request, RESULT_TABLES_IDX resultTable) { + File tempFile = null; + try { + /** + * @see LightCurveProcessor#computePeriodogram(PeriodogramAPIRequest, java.lang.String) + */ + URL url = buildUrl(request); + + File apiResult = apiDownlaod(url); + + tempFile = extractTblFrom(apiResult, resultTable); + + } catch (IOException e) { + e.printStackTrace(); + } catch (FailedRequestException e) { + e.printStackTrace(); + } + return tempFile; + } + + protected File apiDownlaod(URL url) throws IOException, FailedRequestException { + + File apiResultTempFile = makeApiResultTempFile(); + + URLConnection aconn = URLDownload.makeConnection(url); + aconn.setRequestProperty("Accept", "*/*"); + URLDownload.getDataToFile(aconn, apiResultTempFile); //TODO Get from cache + + return apiResultTempFile; + } + + + protected File makeResultTempFile(RESULT_TABLES_IDX resultTable) throws IOException { + String prefix = "error"; + switch (resultTable) { + case PERIODOGRAM: + prefix = "periodogram-"; + break; + case PEAKS: + prefix = "peaks-"; + break; + } + + return File.createTempFile(prefix, ".tbl", ServerContext.getTempWorkDir()); + } + + protected File makeApiResultTempFile() throws IOException { + return File.createTempFile("lc-api-result-", ".xml", ServerContext.getTempWorkDir()); + } +} diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/LightCurveHandler.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/LightCurveHandler.java new file mode 100644 index 0000000000..0e8b7ae25f --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/LightCurveHandler.java @@ -0,0 +1,45 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query.lc; + +import java.io.File; + +/** + * Class should handle the input user parameter to + * call an API to + * get at least the periodogram and peaks table + * out of a raw time changin flux curve + * + * @author ejoliet + * @see PeriodogramAPIRequest + */ +public interface LightCurveHandler { + /** + * TODO check ordinals when API call is implemented + * Represent the tables in votable result from API: 0 for periodogram, 1 for peaks + */ + enum RESULT_TABLES_IDX { + PERIODOGRAM, PEAKS + } + + + /** + * return a periodogram table from a request + * + * @return periodogram (power vs period) file + */ + public File getPeriodogramTable(PeriodogramAPIRequest request); + + /** + * Return the table which contains N peaks, N integer from request object + * + * @return peaks table + * @see PeriodogramAPIRequest#getNumberPeaks() + */ + public File getPeaksTable(PeriodogramAPIRequest request); + + /** + * TODO add extra output parameters getter that might be interesting + */ +} diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/LightCurveProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/LightCurveProcessor.java new file mode 100644 index 0000000000..68ceded935 --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/LightCurveProcessor.java @@ -0,0 +1,155 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query.lc; + +import edu.caltech.ipac.firefly.core.EndUserException; +import edu.caltech.ipac.firefly.data.TableServerRequest; +import edu.caltech.ipac.firefly.server.ServerContext; +import edu.caltech.ipac.firefly.server.query.DataAccessException; +import edu.caltech.ipac.firefly.server.query.IpacTablePartProcessor; +import edu.caltech.ipac.firefly.server.query.SearchProcessorImpl; +import edu.caltech.ipac.firefly.server.util.Logger; +import edu.caltech.ipac.firefly.server.util.QueryUtil; +import edu.caltech.ipac.util.AppProperties; +import edu.caltech.ipac.util.StringUtils; +import edu.caltech.ipac.util.download.FailedRequestException; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * This class takes care of the LC api call and return result IpacTable Data. + */ + +@SearchProcessorImpl(id = "LightCurveProcessor") + +public class LightCurveProcessor extends IpacTablePartProcessor { + + private static final String PERIODOGRAM_API_URL = AppProperties.getProperty("periodogram.host", "default_periodogram_host_url"); + + private static final Logger.LoggerImpl _log = Logger.getLogger(); + + // API will return votable, depending on the request, return either peaks or periodogram table, which names are predefined here: + private static final String PERIODOGRAM_TABLE_NAME = "periodogram_table.tbl"; + private static final String PEAKS_TABLE_NAME = "peaks_table.tbl"; + + /** + * Class handling the API call and returning LC result table + */ + public LightCurveProcessor() { + + // TODO enable the nadler in constructor when the NexsciHandler is ready + // LightCurveHandler h = new IrsaLightCurveHandler() { + } + + /** + * This method is defined as an abstract in the IpacTablePartProcessor and it is implemented here. + * The TableServerRequest is passed here and processed. Only when the "searchRequest" is set, the request + * is processed. + * + * @return File with statistics on a table + * @throws IOException + * @throws DataAccessException + */ + protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { + + PeriodogramAPIRequest req = QueryUtil.assureType(PeriodogramAPIRequest.class, request); + String tblType = req.getParam(PeriodogramAPIRequest.TABLE_NAME); + String tblName = (tblType != null && tblType.equalsIgnoreCase(PeriodogramAPIRequest.RESULT_TABLE)) + ? PERIODOGRAM_TABLE_NAME : PEAKS_TABLE_NAME; + + //In order to get any of those tables, computing the periodogram need to happen: + // Result is a Votable containing 2 tables:periodogram and peaks + File resTable = null; + try { + resTable = computePeriodogram(req, tblName); + } catch (FailedRequestException e) { + e.printStackTrace(); + } + +// if (tblType.equalsIgnoreCase(PeriodogramAPIRequest.PEAKS_TABLE)) { +// +// } + + return resTable; + } + + /** + * From the request, get the file and the algorithm to compute the peridogram by calling external API + * + * @param req request + * @param tblName table name to distinguish them + * @return table file result either peaks por periodogram + * @throws FailedRequestException + */ + public File computePeriodogram(PeriodogramAPIRequest req, String tblName) throws FailedRequestException { + + //Fake call API, parse VOTable result. See for example QueryMOS + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + //TODO this is used with overwritten method. Once API known, remove and use the handler directly + LightCurveHandler h = new IrsaLightCurveHandler() { + + /** + * For testing purposes returned periodogram from here: + * PeriodogramAPIRequest.RESULT_TABLE = "http://web.ipac.caltech.edu/staff/ejoliet/demo/vo-nexsci-result-sample.xml" + * TODO remove after implementing NexsciHandler + * @param req + * @return url api + * @throws MalformedURLException + */ + @Override + protected URL buildUrl(PeriodogramAPIRequest req) throws MalformedURLException { + /** + * For now just download the file from the url from req.getResultTable() + * and stream it out + */ + String SAMPLE_URL = req.getResultTable(); + return new URL(SAMPLE_URL); + } + }; + +// LightCurveHandler h = new IrsaLightCurveHandler(); + if (tblName.equalsIgnoreCase(PERIODOGRAM_TABLE_NAME)) { + return h.getPeriodogramTable(req); + } else if (tblName.equalsIgnoreCase(PEAKS_TABLE_NAME)) { + return h.getPeaksTable(req); + } else { + throw new FailedRequestException("Unable to deal with the request table name " + tblName); + } + } + + private static File makeFileName(PeriodogramAPIRequest req) throws IOException { + return File.createTempFile("lc-result", ".xml", ServerContext.getPermWorkDir()); + } + + private URL createURL(PeriodogramAPIRequest req) throws EndUserException, IOException { + PeriodogramAPIRequest request = (PeriodogramAPIRequest) req.cloneRequest(); + String url = req.getUrl(); + if (url == null || url.length() < 5) { + url = PERIODOGRAM_API_URL; + } + String paramStr = buildParamFrom(request); + if (paramStr.startsWith("&")) { + paramStr = paramStr.substring(1); + } + url += "?" + paramStr; + + return new URL(url); + } + + private String buildParamFrom(PeriodogramAPIRequest request) { + String outputMode = request.getParam(PeriodogramAPIRequest.OUTPUT_MODE); + if (StringUtils.isEmpty(outputMode)) { + outputMode = "VOTable"; + } + return "min_period=0&n_peaks=50"; + } +} diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/PeriodogramAPIRequest.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/PeriodogramAPIRequest.java new file mode 100644 index 0000000000..2066070ac1 --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/PeriodogramAPIRequest.java @@ -0,0 +1,90 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query.lc; + +import edu.caltech.ipac.firefly.data.TableServerRequest; + +/** + * Request class to transport and gets the parameters related to LC + * @author ejoliet + */ +public class PeriodogramAPIRequest extends TableServerRequest { + + public final static String OUTPUT_MODE = "output_`mode"; + + public final static String TABLE_NAME = "table_name"; + // API url + public final static String URL = "url"; + + public final static String LC_FILE = "original_table"; + // Periodogram table + public static final String RESULT_TABLE = "result_table"; + + public static final String FOLDED_TABLE = "folded_table"; + public final static String PERIOD_IN_DAYS = "period_days"; + public final static String TIME_COLUMN_NAME = "time_col_name"; + + // Input table raw LC flux vs time, should at least contain flux and time! + public static final String TIME_DEPENDENT_TABLE = "input_table"; + + public final static String ALGO_NAME = "algo_name"; + + // number of peaks (default = 50) + public final static String NUMBER_PEAKS = "n_peaks"; + public final static String MINIMUM_PERIOD = "min_period"; + public final static String MAXIMUM_PERIOD = "max_period"; + + public final static String STEP_METHOD_NAME = "step_method"; + public final static String STEP_SIZE = "step_size"; + + + public PeriodogramAPIRequest() { + super(PeriodogramAPIRequest.class.getSimpleName()); + } + + public String getUrl() { + return getParam(URL); + } + + /** + * Period value + * + * @return period in days + */ + public float getPeriod() { + return getFloatParam(PERIOD_IN_DAYS); + } + + /** + * @return lc original table file path + */ + public String getLcSource() { + return getParam(LC_FILE); + } + + /** + * Usually 'mjd', but who knows... + * + * @return name of the time column + */ + public String getTimeColName() { + return getParam(TIME_COLUMN_NAME); + } + + public float getMinimumPeriod() { + return getFloatParam(MINIMUM_PERIOD); + } + + public float getMaximumPeriod() { + return getFloatParam(MAXIMUM_PERIOD); + } + + public int getNumberPeaks() { + return getIntParam(NUMBER_PEAKS); + } + + public String getResultTable() { + return getParam(RESULT_TABLE); + } +} diff --git a/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/PhaseFoldedCurveProcessor.java b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/PhaseFoldedCurveProcessor.java new file mode 100644 index 0000000000..11c03cc5cf --- /dev/null +++ b/src/firefly/java/edu/caltech/ipac/firefly/server/query/lc/PhaseFoldedCurveProcessor.java @@ -0,0 +1,123 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query.lc; + +import edu.caltech.ipac.firefly.data.TableServerRequest; +import edu.caltech.ipac.firefly.server.ServerContext; +import edu.caltech.ipac.firefly.server.query.DataAccessException; +import edu.caltech.ipac.firefly.server.query.IpacTablePartProcessor; +import edu.caltech.ipac.firefly.server.query.SearchProcessorImpl; +import edu.caltech.ipac.firefly.server.util.Logger; +import edu.caltech.ipac.firefly.server.util.QueryUtil; +import edu.caltech.ipac.util.FileUtil; +import edu.caltech.ipac.util.StringUtils; +import edu.caltech.ipac.util.download.URLDownload; + +import java.io.File; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +/** + * Created by zhang on 10/14/15. + * This class calculates the statistics of a IpacTable Data. + */ + +@SearchProcessorImpl(id = "PhaseFoldedProcessor") + +public class PhaseFoldedCurveProcessor extends IpacTablePartProcessor { + + private static final Logger.LoggerImpl _log = Logger.getLogger(); + + private static final String FOLDED_TABLE_NAME = "folded_table.tbl"; + private final IrsaLightCurveHandler irsaLcHandler; + + /** + * Class handling the API call and returning LC result table + */ + public PhaseFoldedCurveProcessor() { + irsaLcHandler = new IrsaLightCurveHandler(); + } + + /** + * This method is defined as an abstract in the IpacTablePartProcessor and it is implemented here. + * The TableServerRequest is passed here and processed. Only when the "searchRequest" is set, the request + * is processed. + * + * @return File with statistics on a table + * @throws IOException + * @throws DataAccessException + */ + protected File loadDataFile(TableServerRequest request) throws IOException, DataAccessException { + + PeriodogramAPIRequest req = QueryUtil.assureType(PeriodogramAPIRequest.class, request); + String tblType = req.getParam(PeriodogramAPIRequest.TABLE_NAME); + String tblName = (tblType != null && tblType.equalsIgnoreCase(PeriodogramAPIRequest.FOLDED_TABLE)) + ? FOLDED_TABLE_NAME : "ERROR.tbl"; + + float period = req.getFloatParam("period"); + String lcTable = req.getParam("original_table"); + + + //Votable containing 2 tables:periodogram and peaks + File resTable = null; + try { + resTable = phaseFoldedTable(req); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + return resTable; + } + + protected File phaseFoldedTable(PeriodogramAPIRequest req) throws InterruptedException { + //Fake building phase folded + Thread.sleep(5000); + + + File phaseFoldedTable = irsaLcHandler.toPhaseFoldedTable(getSourceFile(req.getLcSource(), req), req.getPeriod()); + + + return phaseFoldedTable; + } + + private File getSourceFile(String source, TableServerRequest request) { + File inf = null; + try { + URL url = makeUrl(source); + if (url == null) { + inf = ServerContext.convertToFile(source); + } else { + HttpURLConnection conn = (HttpURLConnection) URLDownload.makeConnection(url); + int rcode = conn.getResponseCode(); + if (rcode >= 200 && rcode < 400) { + String sfname = URLDownload.getSugestedFileName(conn); + if (sfname == null) { + sfname = url.getPath(); + } + String ext = sfname == null ? null : FileUtil.getExtension(sfname); + ext = StringUtils.isEmpty(ext) ? ".ul" : "." + ext; + inf = createFile(request, ext); + URLDownload.getDataToFile(conn, inf, null, false, true, true, Long.MAX_VALUE); + } + } + } catch (Exception ex) { + inf = null; + } + if (inf != null && inf.canRead()) { + return inf; + } + + return null; + } + + private URL makeUrl(String source) { + try { + return new URL(source); + } catch (MalformedURLException e) { + return null; + } + } +} diff --git a/src/firefly/js/ui/TestQueriesPanel.jsx b/src/firefly/js/ui/TestQueriesPanel.jsx index 238e8ad178..8162f488ab 100644 --- a/src/firefly/js/ui/TestQueriesPanel.jsx +++ b/src/firefly/js/ui/TestQueriesPanel.jsx @@ -36,7 +36,7 @@ import {RadioGroupInputField} from './RadioGroupInputField.jsx'; import {ListBoxInputField} from './ListBoxInputField.jsx'; import {FileUpload} from '../ui/FileUpload.jsx'; import {parseWorldPt} from '../visualize/Point.js'; -import {makeTblRequest, makeIrsaCatalogRequest} from '../tables/TableUtil.js'; +import {makeTblRequest, makeFileRequest, makeIrsaCatalogRequest} from '../tables/TableUtil.js'; import {dispatchAddImages,getAViewFromMultiView,getMultiViewRoot} from '../visualize/MultiViewCntlr.js'; import WebPlotRequest from '../visualize/WebPlotRequest.js'; import {dispatchPlotImage} from '../visualize/ImagePlotCntlr.js'; @@ -44,10 +44,10 @@ import {getDS9Region} from '../rpc/PlotServicesJson.js'; import {Region} from '../visualize/region/Region.js'; import {RegionFactory} from '../visualize/region/RegionFactory.js'; -const options= [ - {label: 'AllWISE Source Catalog', value:'wise_allwise_p3as_psd', proj:'WISE'}, - {label: '2MASS All-Sky Point Source Catalog (PSC)', value:'fp_psc', proj:'2MASS'}, - {label: 'IRAS Point Source Catalog v2.1 (PSC)', value:'iraspsc', proj: 'IRAS'} +const options = [ + {label: 'AllWISE Source Catalog', value: 'wise_allwise_p3as_psd', proj: 'WISE'}, + {label: '2MASS All-Sky Point Source Catalog (PSC)', value: 'fp_psc', proj: '2MASS'}, + {label: 'IRAS Point Source Catalog v2.1 (PSC)', value: 'iraspsc', proj: 'IRAS'} ]; @@ -59,18 +59,18 @@ export class TestQueriesPanel extends Component { componentWillUnmount() { if (this.removeListener) this.removeListener(); - this.iAmMounted= false; + this.iAmMounted = false; } componentDidMount() { - this.iAmMounted= true; - this.removeListener= FieldGroupUtils.bindToStore('TEST_CAT_PANEL', (fields) => { + this.iAmMounted = true; + this.removeListener = FieldGroupUtils.bindToStore('TEST_CAT_PANEL', (fields) => { if (this.iAmMounted) this.setState(fields); }); } render() { - const fields= this.state; + const fields = this.state; return (

- + {renderCatalogTab()} {renderImagesTab()} -
{renderWiseSearch(fields)}
-
{render2MassSearch(fields)}
-
{renderLoadRegion(fields)}
- + +
{renderWiseSearch(fields)}
+
+ +
{render2MassSearch(fields)}
+
+ +
{renderLoadRegion(fields)}
+
+ +
{renderPeriodogram()}
+
@@ -101,9 +109,6 @@ export class TestQueriesPanel extends Component { } - - - TestQueriesPanel.propTypes = { name: PropTypes.oneOf(['TestSearches']), }; @@ -117,51 +122,103 @@ function hideSearchPanel() { dispatchHideDropDown(); } +function renderPeriodogram() { + + /** + * + * @param isPeriodogram + */ + function lightCurveSubmit(isPeriodogram) { + console.log('periodogram...'); + let tReq; + //var tReq = makeTblRequest('PhaseFoldedProcessor', 'Phase folded', { period: '1', 'table_name':'folded_table','original_table':}); + if (isPeriodogram) { + tReq = makeTblRequest('LightCurveProcessor', 'Periodogram', { + 'table_name': 'periodogram', + 'result_table': 'http://web.ipac.caltech.edu/staff/ejoliet/demo/vo-nexsci-result-sample.xml' + }); + } else { + tReq = makeTblRequest('PhaseFoldedProcessor', 'Phase folded', { + 'period_days': '1', + 'table_name': 'folded_table', + //'original_table': 'file:///Users/ejoliet/Documents/IPAC/ipac_samples/AllWISE-MEP-m82-2targets-10arsecs.tbl' + 'original_table': 'http://web.ipac.caltech.edu/staff/ejoliet/demo/AllWISE-MEP-m82-2targets-10arsecs.tbl' + }); + } + + dispatchTableSearch(tReq); + } + + return ( +
+ + +
+ +
+ + +
+ ); +} + function renderCatalogTab() { return (
- + }}/>
- ); + ); } - -const wiseBandMap= { - 'allwise-multiband' : ['1','2','3','4'], - 'allsky_4band-1b' :['1','2','3','4'], - 'allsky_4band-3a' :['1','2','3','4'], - 'cryo_3band-1b' :['1','2','3'], - 'cryo_3band-1b-3a' :['1','2','3'], - 'postcryo-1b' :['1','2'] +const wiseBandMap = { + 'allwise-multiband': ['1', '2', '3', '4'], + 'allsky_4band-1b': ['1', '2', '3', '4'], + 'allsky_4band-3a': ['1', '2', '3', '4'], + 'cryo_3band-1b': ['1', '2', '3'], + 'cryo_3band-1b-3a': ['1', '2', '3'], + 'postcryo-1b': ['1', '2'] }; function renderWiseSearch(fields) { - const ds= get(fields,'wiseDataSet.value', 'allwise-multiband'); - const options= wiseBandMap[ds].map( (w) => ({label:'W'+w, value:w })); + const ds = get(fields, 'wiseDataSet.value', 'allwise-multiband'); + const options = wiseBandMap[ds].map((w) => ({label: 'W' + w, value: w})); return (
@@ -188,7 +245,7 @@ function renderWiseSearch(fields) {
); - -} +} function renderLoadRegion(fields) { return (
@@ -261,7 +317,20 @@ function renderLoadRegion(fields) { } +function renderCatalogFromSource(fields) { + return ( +
+ +
+ ); +} function renderImagesTab() { @@ -284,24 +353,24 @@ function renderImagesTab() { function onSearchSubmit(request) { console.log(request); - const wp= parseWorldPt(request[ServerParams.USER_TARGET_WORLD_PT]); + const wp = parseWorldPt(request[ServerParams.USER_TARGET_WORLD_PT]); if (!wp) { showInfoPopup('Target is required'); return; } - if (request.Tabs==='catalog') { + if (request.Tabs === 'catalog') { doCatalog(request); } - else if (request.Tabs==='images') { + else if (request.Tabs === 'images') { doImages(request); } - else if (request.Tabs==='wiseImage') { + else if (request.Tabs === 'wiseImage') { doWise(request); } - else if (request.Tabs==='2massImage') { + else if (request.Tabs === '2massImage') { do2Mass(request); } - else if (request.Tabs==='loadRegion') { + else if (request.Tabs === 'loadRegion') { doRegionLoad(request); } else { @@ -311,32 +380,31 @@ function onSearchSubmit(request) { function doCatalog(request) { var tReq = makeIrsaCatalogRequest( - request.catalog, - options.find( (op) => request.catalog===op.value).proj, - request.catalog, - { - [ServerParams.USER_TARGET_WORLD_PT] : request[ServerParams.USER_TARGET_WORLD_PT], - SearchMethod: 'Cone', - radius : request.radius, - }); + request.catalog, + options.find((op) => request.catalog === op.value).proj, + request.catalog, + { + [ServerParams.USER_TARGET_WORLD_PT]: request[ServerParams.USER_TARGET_WORLD_PT], + SearchMethod: 'Cone', + radius: request.radius, + }); dispatchTableSearch(tReq); } function doImages(request) { - var wp= parseWorldPt(request.UserTargetWorldPt); + var wp = parseWorldPt(request.UserTargetWorldPt); // -example call to 2mass //var wpr1= WebPlotRequest.makePlotServiceReq(ServiceType.TWOMASS, wp,'h',.1 ); //var wpr2= WebPlotRequest.makePlotServiceReq(ServiceType.TWOMASS, wp,'k',.1 ); - // -example call to wise - var wpr1= WebPlotRequest.makeWiseRequest(wp,'1b','1',.4 ); - var wpr2= WebPlotRequest.makeWiseRequest(wp,'1b','2',.4 ); - var wpr3= WebPlotRequest.makeWiseRequest(wp,'1b','3',.4 ); - var wpr4= WebPlotRequest.makeWiseRequest(wp,'1b','4',.4 ); + var wpr1 = WebPlotRequest.makeWiseRequest(wp, '1b', '1', .4); + var wpr2 = WebPlotRequest.makeWiseRequest(wp, '1b', '2', .4); + var wpr3 = WebPlotRequest.makeWiseRequest(wp, '1b', '3', .4); + var wpr4 = WebPlotRequest.makeWiseRequest(wp, '1b', '4', .4); // -example call to IRIS @@ -363,8 +431,6 @@ function doImages(request) { wpr4.setGroupLocked(true); - - wpr1.setInitialZoomLevel(parseFloat(request.zoom)); wpr2.setInitialZoomLevel(parseFloat(request.zoom)); wpr3.setInitialZoomLevel(parseFloat(request.zoom)); @@ -374,9 +440,9 @@ function doImages(request) { //=========== 3 color - var cWpr1= WebPlotRequest.makeWiseRequest(wp,'3a','1',.4 ); - var cWpr2= WebPlotRequest.makeWiseRequest(wp,'3a','2',.4 ); - var cWpr3= WebPlotRequest.makeWiseRequest(wp,'3a','3',.4 ); + var cWpr1 = WebPlotRequest.makeWiseRequest(wp, '3a', '1', .4); + var cWpr2 = WebPlotRequest.makeWiseRequest(wp, '3a', '2', .4); + var cWpr3 = WebPlotRequest.makeWiseRequest(wp, '3a', '3', .4); cWpr1.setPlotGroupId('test-group'); cWpr2.setPlotGroupId('test-group'); cWpr3.setPlotGroupId('test-group'); @@ -386,70 +452,67 @@ function doImages(request) { cWpr3.setInitialZoomLevel(parseFloat(request.zoom)); + //wpr1.setAnnotationOps(AnnotationOps.TITLE_BAR); + dispatchPlotImage({plotId: 'TestImage1', wpRequest: wpr1}); + dispatchPlotImage({plotId: 'TestImage2', wpRequest: wpr2}); + dispatchPlotImage({plotId: 'TestImage3', wpRequest: wpr3}); + dispatchPlotImage({plotId: 'TestImage4', wpRequest: wpr4}); + dispatchPlotImage({plotId: 'TestImage3Color', wpRequest: [cWpr1, cWpr2, cWpr3]}); - //wpr1.setAnnotationOps(AnnotationOps.TITLE_BAR); - dispatchPlotImage({plotId:'TestImage1', wpRequest:wpr1}); - dispatchPlotImage({plotId:'TestImage2', wpRequest:wpr2}); - dispatchPlotImage({plotId:'TestImage3', wpRequest:wpr3}); - dispatchPlotImage({plotId:'TestImage4', wpRequest:wpr4}); - - dispatchPlotImage({plotId:'TestImage3Color', wpRequest:[cWpr1,cWpr2,cWpr3]}); - - var viewer= getAViewFromMultiView(getMultiViewRoot()); + var viewer = getAViewFromMultiView(getMultiViewRoot()); dispatchAddImages(viewer.viewerId, ['TestImage1', 'TestImage2', 'TestImage3', 'TestImage4', 'TestImage3Color']); dispatchHideDropDown(); } -const schemaParams= { - 'allwise-multiband': {ImageSet:'allwise-multiband', ProductLevel:'3a', title:'AllWISE' } , - 'allsky_4band-1b': {ImageSet:'allsky-4band', ProductLevel:'1b', title:'AllSky - Single' }, - 'allsky_4band-3a': {ImageSet:'allsky-4band', ProductLevel:'3a', title:'AllSky - Atlas' }, - 'cryo_3band-1b': {ImageSet:'cryo_3band', ProductLevel:'1b' , title:'3-Band Single'}, - 'cryo_3band-1b-3a': {ImageSet:'cryo_3band', ProductLevel:'3a', title:'3-Band Atlas' }, - 'postcryo-1b': {ImageSet:'postcryo', ProductLevel:'1b' , title:'Post-Cryo'}, - 'neowiser-1b': {ImageSet:'neowiser', ProductLevel:'1b', title:'NeoWISER' } +const schemaParams = { + 'allwise-multiband': {ImageSet: 'allwise-multiband', ProductLevel: '3a', title: 'AllWISE'}, + 'allsky_4band-1b': {ImageSet: 'allsky-4band', ProductLevel: '1b', title: 'AllSky - Single'}, + 'allsky_4band-3a': {ImageSet: 'allsky-4band', ProductLevel: '3a', title: 'AllSky - Atlas'}, + 'cryo_3band-1b': {ImageSet: 'cryo_3band', ProductLevel: '1b', title: '3-Band Single'}, + 'cryo_3band-1b-3a': {ImageSet: 'cryo_3band', ProductLevel: '3a', title: '3-Band Atlas'}, + 'postcryo-1b': {ImageSet: 'postcryo', ProductLevel: '1b', title: 'Post-Cryo'}, + 'neowiser-1b': {ImageSet: 'neowiser', ProductLevel: '1b', title: 'NeoWISER'} }; function doWise(request) { - console.log('wise',request); - var tgtName= ''; - const wp= parseWorldPt(request[ServerParams.USER_TARGET_WORLD_PT]); - if (wp.getObjName()) tgtName= ', ' +wp.getObjName(); + console.log('wise', request); + var tgtName = ''; + const wp = parseWorldPt(request[ServerParams.USER_TARGET_WORLD_PT]); + if (wp.getObjName()) tgtName = ', ' + wp.getObjName(); const params = Object.assign(schemaParams[request.wiseDataSet], - { - [ServerParams.USER_TARGET_WORLD_PT] : request[ServerParams.USER_TARGET_WORLD_PT], - mission: 'wise', - intersect: request.intersect, - mcenter: (request.intersect==='CENTER' || request.intersect==='COVERS') ? request.mcenter : 'all', - size: request.size, - subsize: request.subsize, - band : request.wisebands - }); - const reqParams= makeTblRequest('ibe_processor', `${schemaParams[request.wiseDataSet].title}${tgtName}`, params); + { + [ServerParams.USER_TARGET_WORLD_PT]: request[ServerParams.USER_TARGET_WORLD_PT], + mission: 'wise', + intersect: request.intersect, + mcenter: (request.intersect === 'CENTER' || request.intersect === 'COVERS') ? request.mcenter : 'all', + size: request.size, + subsize: request.subsize, + band: request.wisebands + }); + const reqParams = makeTblRequest('ibe_processor', `${schemaParams[request.wiseDataSet].title}${tgtName}`, params); dispatchTableSearch(reqParams); } function do2Mass(request) { - console.log('wmass',request); - const reqParams= makeTblRequest('ibe_processor', '2MASS-' + request[ServerParams.USER_TARGET_WORLD_PT], - { - [ServerParams.USER_TARGET_WORLD_PT] : request[ServerParams.USER_TARGET_WORLD_PT], - mission: 'twomass', - ds : request.ds, - band : request.band - }); + console.log('wmass', request); + const reqParams = makeTblRequest('ibe_processor', '2MASS-' + request[ServerParams.USER_TARGET_WORLD_PT], + { + [ServerParams.USER_TARGET_WORLD_PT]: request[ServerParams.USER_TARGET_WORLD_PT], + mission: 'twomass', + ds: request.ds, + band: request.band + }); dispatchTableSearch(reqParams); } - function doRegionLoad(request) { getDS9Region(request.fileUpload) - .then( (result) => { + .then((result) => { //console.log(result); if (result.RegionData) { diff --git a/src/firefly/test/edu/caltech/ipac/firefly/server/query/LightCurveProcessorTest.java b/src/firefly/test/edu/caltech/ipac/firefly/server/query/LightCurveProcessorTest.java new file mode 100644 index 0000000000..924e94f486 --- /dev/null +++ b/src/firefly/test/edu/caltech/ipac/firefly/server/query/LightCurveProcessorTest.java @@ -0,0 +1,295 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query; + +import edu.caltech.ipac.astro.IpacTableException; +import edu.caltech.ipac.astro.IpacTableReader; +import edu.caltech.ipac.firefly.server.query.lc.IrsaLightCurveHandler; +import edu.caltech.ipac.firefly.server.query.lc.LightCurveHandler; +import edu.caltech.ipac.firefly.server.query.lc.PeriodogramAPIRequest; +import edu.caltech.ipac.util.DataGroup; +import edu.caltech.ipac.util.DataObject; +import edu.caltech.ipac.util.DataType; +import edu.caltech.ipac.util.download.FailedRequestException; +import edu.caltech.ipac.util.download.URLDownload; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; + +/** + * Created by ejoliet on 8/23/16. + */ +public class LightCurveProcessorTest { + + + private static PeriodogramAPIRequestTest req; + private static File rawTable; + + + @BeforeClass + public static void setUp() { + req = new PeriodogramAPIRequestTest(); + try { + rawTable = File.createTempFile("phasefolded-temp-", ".tbl", new File(".")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Test + public void testGetPeriodogram() { + + boolean deleteOnExit = true; + LightCurveHandler t = new IrsaLightCurveHandler() { + @Override + protected URL buildUrl(PeriodogramAPIRequest req) throws MalformedURLException { + return new URL(req.getResultTable()); + } + + @Override + protected File makeResultTempFile(RESULT_TABLES_IDX resultTable) throws IOException { + File tmpFile = File.createTempFile("period-test-", ".tbl", new File(".")); + if (deleteOnExit) { + tmpFile.deleteOnExit(); + } + return tmpFile; + } + + @Override + protected File makeApiResultTempFile() throws IOException { + File tmpFile = File.createTempFile("votable-test-", ".xml", new File(".")); + if (deleteOnExit) { + tmpFile.deleteOnExit(); + } + return tmpFile; + } + }; + + File p = t.getPeriodogramTable(req); + + try { + DataGroup inDataGroup = IpacTableReader.readIpacTable(p, "periodogram"); + List dgjList = inDataGroup.values(); + DataType[] inColumns = inDataGroup.getDataDefinitions(); + Assert.assertTrue(inColumns.length + " is not 2", inColumns.length == 2); + Assert.assertTrue("expected " + dgjList.size(), dgjList.size() == 390); + } catch (IpacTableException e) { + e.printStackTrace(); + } + + } + + @Test + public void testGetPeaks() { + + boolean deleteOnExit = true; + LightCurveHandler t = new IrsaLightCurveHandler() { + @Override + protected URL buildUrl(PeriodogramAPIRequest req) throws MalformedURLException { + return new URL(req.getResultTable()); + } + + @Override + protected File makeResultTempFile(RESULT_TABLES_IDX resultTable) throws IOException { + File tmpFile = File.createTempFile("peaks-test-", ".tbl", new File(".")); + if (deleteOnExit) { + tmpFile.deleteOnExit(); + } + return tmpFile; + } + + @Override + protected File makeApiResultTempFile() throws IOException { + File tmpFile = File.createTempFile("votable-test-", ".xml", new File(".")); + if (deleteOnExit) { + tmpFile.deleteOnExit(); + } + return tmpFile; + } + }; + + File peaks = t.getPeaksTable(req); + + try { + DataGroup inPeaksDataGroup = IpacTableReader.readIpacTable(peaks, "peaks"); + DataType[] inColumns = inPeaksDataGroup.getDataDefinitions(); + Assert.assertTrue(inColumns.length + " is not 5", inColumns.length == 5); + List dgjList = inPeaksDataGroup.values(); + inColumns = inPeaksDataGroup.getDataDefinitions(); + Assert.assertTrue("expected " + dgjList.size(), dgjList.size() == req.getNumberPeaks()); + } catch (IpacTableException e) { + e.printStackTrace(); + } + + } + + @Test + public void testPhaseFoldedCurve() { + + boolean deleteOnExit = true; + if(deleteOnExit){ + rawTable.deleteOnExit(); + } + IrsaLightCurveHandler t = new IrsaLightCurveHandler() { + + private File getUnchangedTable(File tbl){ + return tbl; + } + @Override + public File toPhaseFoldedTable(File tbl, float period) { + //return same table for now, once implemented, plug the right code here + return getUnchangedTable(tbl); + } + }; + + DataGroup inDataGroup = null; + try { + inDataGroup = IpacTableReader.readIpacTable(new File(req.getLcSource()), "lc_raw"); + } catch (IpacTableException e) { + e.printStackTrace(); + } + List dgjListOrigin = inDataGroup.values(); + DataType[] inColumns = inDataGroup.getDataDefinitions(); + + File p = t.toPhaseFoldedTable(new File(req.getLcSource()), req.getPeriod()); + + try { + inDataGroup = IpacTableReader.readIpacTable(p, "phasefolded"); + List dgjList = inDataGroup.values(); + DataType[] inColumnsPhaseFolded = inDataGroup.getDataDefinitions(); + //should be one more extra column (Phase) + Assert.assertTrue(inColumns.length + " is not correct", inColumns.length == inColumnsPhaseFolded.length); //-1 when phasefold is introduced, test it + Assert.assertTrue("expected " + dgjList.size(), dgjList.size() == dgjListOrigin.size()); + } catch (IpacTableException e) { + e.printStackTrace(); + } + + } + + /** + * Class that will support a request test + */ + static class PeriodogramAPIRequestTest extends PeriodogramAPIRequest { + + @Override + public float getPeriod() { + return 0.5f; + } + + @Override + public String getLcSource() { + try { + URL demo = new URL("http://web.ipac.caltech.edu/staff/ejoliet/demo/AllWISE-MEP-m82-2targets-10arsecs.tbl"); + URLConnection uc = URLDownload.makeConnection(demo); + URLDownload.getDataToFile(uc, rawTable); + return rawTable.getAbsolutePath(); + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (FailedRequestException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public int getNumberPeaks() { + return 50; + } + + /** + * @return the built url api + */ + @Override + public String getUrl() { + //As for the test, we return the result table + return getResultTable(); + } + + @Override + public String getResultTable() { + return "http://web.ipac.caltech.edu/staff/ejoliet/demo/vo-nexsci-result-sample.xml"; + } + } + + /** + * Could be useful to define algorithm with default parameter and use them by mapping an enum from the request to ease the URL API building + * Example of classes below + */ + + class LombScargle implements Periodogram { + + + @Override + public AlgorithmDefinition getAlgoDef() { + return AlgorithmDefinition.LS; + } + + @Override + public int getNPeaks() { + return 50; + } + + @Override + public Period getPeriod() { + return new PeriodSample(); + } + + @Override + public double[] getAlgoValues() { + return new double[0]; + } + + @Override + public StepMethod getStepMethod(StepMethod.STEPMETHOD_NAME sName) { + return new FixedPeriodMethod(0.1f); + } + } + + class FixedPeriodMethod implements StepMethod { + + private final float val; + + FixedPeriodMethod(float step) { + this.val = step; + } + + @Override + public String getName() { + return STEPMETHOD_NAME.FIXED_PERIOD.name(); + } + + @Override + public float getValue() { + return val; + } + } + + protected class PeriodSample implements Period { + + @Override + public float getMin() { + return 0; + } + + @Override + public float getMax() { + return 10; + } + + @Override + public float getPeakValue() { + return 2; + } + } +} + diff --git a/src/firefly/test/edu/caltech/ipac/firefly/server/query/Periodogram.java b/src/firefly/test/edu/caltech/ipac/firefly/server/query/Periodogram.java new file mode 100644 index 0000000000..6270ac93ba --- /dev/null +++ b/src/firefly/test/edu/caltech/ipac/firefly/server/query/Periodogram.java @@ -0,0 +1,82 @@ +/* + * License information at https://github.com/Caltech-IPAC/firefly/blob/master/License.txt + */ +package edu.caltech.ipac.firefly.server.query; + +/** + * Utilities classes to help (pre)define periodogram algorithm + * + * @author ejoliet + */ +public interface Periodogram { + + public enum AlgorithmDefinition { + + LS("Lomb-Scargle"); + + String name = null; + int nParameters = 0; + + AlgorithmDefinition(String name) { + this.name = name; + } + + AlgorithmDefinition(String name, int npars) { + this.name = name; + this.nParameters = npars; + } + + public int getNParameters() { + return this.nParameters; + } + + public String getName() { + return this.name; + } + } + + /** + * @return algo definition used to compute this + */ + public AlgorithmDefinition getAlgoDef(); + + /** + * @return number of peaks + */ + public int getNPeaks(); + + /** + * @return the Period object + */ + public Period getPeriod(); // using min, max, see Period + + /** + * @return array of values of size defined by AlgorithmDefinition#getNParameters + */ + public double[] getAlgoValues(); // see AlgorithmDefinition#getNParameters() + + public StepMethod getStepMethod(StepMethod.STEPMETHOD_NAME sName); +} + +/** + * Period interface to handle periodogram period range used and value peak result + */ +interface Period { + + float getMin(); + + float getMax(); + + float getPeakValue(); +} + +/** + * Handle step method definition, expecting a name and a step size associated + */ +interface StepMethod { + enum STEPMETHOD_NAME {FIXED_PERIOD, FIXED_FREQUENCY} + + String getName(); + + float getValue(); //Step size for fixed step methods +} \ No newline at end of file