VStarScriptingAPI.java
/**
* VStar: a statistical analysis tool for variable star data.
* Copyright (C) 2010 AAVSO (http://www.aavso.org/)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aavso.tools.vstar.scripting;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.aavso.tools.vstar.data.SeriesType;
import org.aavso.tools.vstar.data.ValidObservation;
import org.aavso.tools.vstar.exception.AlgorithmError;
import org.aavso.tools.vstar.exception.ObservationReadError;
import org.aavso.tools.vstar.input.database.VSXWebServiceStarInfoSource;
import org.aavso.tools.vstar.plugin.InputType;
import org.aavso.tools.vstar.plugin.ModelCreatorPluginBase;
import org.aavso.tools.vstar.plugin.ObservationSinkPluginBase;
import org.aavso.tools.vstar.plugin.ObservationSourcePluginBase;
import org.aavso.tools.vstar.plugin.model.impl.ApacheCommonsPolynomialFitCreatorPlugin;
import org.aavso.tools.vstar.plugin.ob.src.impl.AIDWebServiceObservationSourcePluginBase;
import org.aavso.tools.vstar.ui.MenuBar;
import org.aavso.tools.vstar.ui.dialog.MessageBox;
import org.aavso.tools.vstar.ui.mediator.AnalysisType;
import org.aavso.tools.vstar.ui.mediator.Mediator;
import org.aavso.tools.vstar.ui.mediator.StarInfo;
import org.aavso.tools.vstar.ui.mediator.ViewModeType;
import org.aavso.tools.vstar.ui.mediator.message.AnalysisTypeChangeMessage;
import org.aavso.tools.vstar.ui.model.plot.ObservationAndMeanPlotModel;
import org.aavso.tools.vstar.ui.resources.PluginLoader;
import org.aavso.tools.vstar.util.locale.LocaleProps;
import org.aavso.tools.vstar.util.model.IModel;
import org.aavso.tools.vstar.util.notification.Listener;
import org.aavso.tools.vstar.util.period.PeriodAnalysisCoordinateType;
import org.aavso.tools.vstar.util.period.dcdft.DcDftAnalysisType;
import org.aavso.tools.vstar.util.period.dcdft.TSDcDft;
import org.aavso.tools.vstar.util.period.wwz.WWZCoordinateType;
import org.aavso.tools.vstar.util.period.wwz.WWZStatistic;
import org.aavso.tools.vstar.util.period.wwz.WeightedWaveletZTransform;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* This is VStar's scripting Application Programming Interface. An instance of
* this class will be passed to scripts.
*
* All methods are synchronised to ensure that only one API method is being
* called at a time.
*/
public class VStarScriptingAPI {
private Mediator mediator;
private static VStarScriptingAPI instance;
private AnalysisTypeChangeMessage analysisTypeMsg;
/**
* Constructor
*/
private VStarScriptingAPI() {
mediator = Mediator.getInstance();
analysisTypeMsg = null;
mediator.getAnalysisTypeChangeNotifier().addListener(createAnalysisTypeChangeListener());
}
/**
* Return Singleton.
*/
public static VStarScriptingAPI getInstance() {
if (instance == null) {
instance = new VStarScriptingAPI();
}
return instance;
}
/**
* Return an analysis type change listener.
*/
private Listener<AnalysisTypeChangeMessage> createAnalysisTypeChangeListener() {
return new Listener<AnalysisTypeChangeMessage>() {
@Override
public void update(AnalysisTypeChangeMessage info) {
analysisTypeMsg = info;
}
@Override
public boolean canBeRemoved() {
return false;
}
};
}
// ***************************************
// ** VStar scripting API methods start **
// ***************************************
/**
* Load a dataset from the specified path. This is equivalent to "File -> New
* Star from File..."
*
* @param path The path to the file.
*/
public synchronized void loadFromFile(final String path) {
commonLoadFromFile(path, false);
}
/**
* Load a dataset from the specified path, adding it to the existing dataset.
*
* @param path The path to the file.
*/
public synchronized void additiveLoadFromFile(final String path) {
commonLoadFromFile(path, true);
}
/**
* Load a dataset from the specified URL.
*
* @param url The URL of the file.
*/
public synchronized void loadFromURL(final String path) {
commonLoadFromURL(path, false);
}
/**
* Load a dataset from the specified path, adding it to the existing dataset.
*
* @param url The URL of the file.
*/
public synchronized void additiveLoadFromURL(final String path) {
commonLoadFromURL(path, true);
}
/**
* Load a dataset from the specified path using the (possibly partial) plug-in
* name to identify the observation source plug-in to use. This is equivalent to
* plugin display name.
*
* @param pluginName The sub-string with which to match the plug-in name.
* @param path The path to the file.
*/
public synchronized void loadFromFile(final String pluginName, final String path) {
commonLoadFromFileOrURLViaPlugin(pluginName, InputType.FILE, path, false);
}
/**
* Load a dataset from the specified path, adding it to the existing dataset
* using the (possibly partial) plug-in name to identify the observation source
* plug-in to use. his is equivalent to plugin display name with the additive
* checkbox selected.
*
* @param pluginName The sub-string with which to match the plug-in name.
* @param path The path to the file.
*/
public synchronized void additiveLoadFromFile(final String pluginName, final String path) {
commonLoadFromFileOrURLViaPlugin(pluginName, InputType.FILE, path, true);
}
/**
* Load a dataset from the specified URL using the (possibly partial) plug-in
* name to identify the observation source plug-in to use.
*
* @param pluginName The sub-string with which to match the plug-in name.
* @param url The URL.
*/
public synchronized void loadFromURL(final String pluginName, final String url) {
commonLoadFromFileOrURLViaPlugin(pluginName, InputType.URL, url, false);
}
/**
* Load a dataset from the specified URL, adding it to the existing dataset,
* using the (possibly partial) plug-in name to identify the observation source
* plug-in to use.
*
* @param pluginName The sub-string with which to match the plug-in name.
* @param url The URL.
*/
public synchronized void additiveLoadFromURL(final String pluginName, final String url) {
commonLoadFromFileOrURLViaPlugin(pluginName, InputType.URL, url, true);
}
/**
* Load a dataset from the AAVSO international database.
*
* @param name The name (not AUID) of the object.
* @param minJD The minimum JD of the range to be loaded.
* @param maxJD The maximum JD of the range to be loaded.
*/
public synchronized void loadFromAID(final String name, double minJD, double maxJD) {
commonLoadFromAID(name, minJD, maxJD, null, null, false, false);
}
/**
* Load a dataset from the AAVSO international database.
*
* @param name The name (not AUID) of the object.
* @param minJD The minimum JD of the range to be loaded.
* @param maxJD The maximum JD of the range to be loaded.
* @param bands A short band name.
* @oaram obscodes A comma-delimited list of observer codes or null for all
* available observer codes.
* @param loadMinimalFields Load a minimal field subset?
*/
public synchronized void loadFromAID(final String name, double minJD, double maxJD, String bands, String obscodes,
boolean loadMinimalFields) {
commonLoadFromAID(name, minJD, maxJD, bands, obscodes, loadMinimalFields, false);
}
/**
* Load a dataset from the AAVSO international database, adding it to the
* existing dataset.
*
* @param name The name (not AUID) of the object.
* @param minJD The minimum JD of the range to be loaded.
* @param maxJD The maximum JD of the range to be loaded.
*/
public synchronized void additiveLoadFromAID(final String name, double minJD, double maxJD) {
commonLoadFromAID(name, minJD, maxJD, null, null, false, true);
}
/**
* Load a dataset from the AAVSO international database, adding it to the
* existing dataset.
*
* @param name The name (not AUID) of the object.
* @param minJD The minimum JD of the range to be loaded.
* @param maxJD The maximum JD of the range to be loaded.
* @param bands A short band name.
* @oaram obscodes A comma-delimited list of observer codes or null for all
* available observer codes.
* @param loadMinimalFields Load a minimal field subset?
*/
public synchronized void additiveLoadFromAID(final String name, double minJD, double maxJD, String bands,
String obscodes, boolean loadMinimalFields) {
commonLoadFromAID(name, minJD, maxJD, bands, obscodes, loadMinimalFields, true);
}
// TODO: add loadFromAID(name) => all
/**
* Return a StarInfo object for named object.
*
* @param name The name (not AUID) of the object.
* @return The StarInfo object.
*/
public synchronized StarInfo getStarInfo(String name) {
init();
VSXWebServiceStarInfoSource infoSrc = new VSXWebServiceStarInfoSource();
return infoSrc.getStarByName(name);
}
/**
* Save the raw or phase plot dataset (according to current mode) to a file of
* rows of values separated by the specified delimiter.
*
* @param path The path to the file to save to (as a string).
* @param delimiter The delimiter between data items.
*/
public synchronized void saveObsList(final String path, String delimiter) {
init();
ObservationSinkPluginBase obSinkPlugin = getObsSinkPlugin(LocaleProps.get("TEXT_FORMAT_FILE"));
if (obSinkPlugin != null) {
mediator.saveObsListToFile(Mediator.getUI().getComponent(), obSinkPlugin, new File(path), delimiter);
}
mediator.waitForJobCompletion();
}
/**
* Save the raw or phase plot mean list (according to current mode) to a file of
* rows of values separated by the specified delimiter.
*
* @param path The path to the file to save to (as a string).
* @param delimiter The delimiter between data items.
*/
public synchronized void saveMeanList(final String path, String delimiter) {
init();
ObservationSinkPluginBase obSinkPlugin = getObsSinkPlugin(LocaleProps.get("TEXT_FORMAT_FILE"));
if (obSinkPlugin != null) {
mediator.saveSyntheticObsListToFile(Mediator.getUI().getComponent(), obSinkPlugin,
ViewModeType.LIST_MEANS_MODE, new File(path), delimiter);
}
mediator.waitForJobCompletion();
}
/**
* Save the raw or phase plot model list (according to current mode) to a file
* of rows of values separated by the specified delimiter.
*
* @param path The path to the file to save to (as a string).
* @param delimiter The delimiter between data items.
*/
public synchronized void saveModelList(final String path, String delimiter) {
init();
ObservationSinkPluginBase obSinkPlugin = getObsSinkPlugin(LocaleProps.get("TEXT_FORMAT_FILE"));
if (obSinkPlugin != null) {
mediator.saveSyntheticObsListToFile(Mediator.getUI().getComponent(), obSinkPlugin, ViewModeType.MODEL_MODE,
new File(path), delimiter);
}
mediator.waitForJobCompletion();
}
/**
* Save the raw or phase plot residual list (according to current mode) to a
* file of rows of values separated by the specified delimiter.
*
* @param path The path to the file to save to (as a string).
* @param delimiter The delimiter between data items.
*/
public synchronized void saveResidualList(final String path, String delimiter) {
init();
ObservationSinkPluginBase obSinkPlugin = getObsSinkPlugin(LocaleProps.get("TEXT_FORMAT_FILE"));
if (obSinkPlugin != null) {
mediator.saveSyntheticObsListToFile(Mediator.getUI().getComponent(), obSinkPlugin,
ViewModeType.RESIDUALS_MODE, new File(path), delimiter);
}
mediator.waitForJobCompletion();
}
/**
* Save the light curve for the current view mode (raw or phase plot) to a PNG
* image file.
*
* @param path The path to the file to save to (as a string).
* @param width The desired width of the image.
* @param height The desired height of the image.
*/
public synchronized void saveLightCurve(final String path, int width, int height) {
init();
mediator.saveCurrentPlotToFile(new File(path), width, height);
}
/**
* Switch to phase plot mode. If no phase plot has been created yet, this will
* open the phase parameter dialog.
*/
public synchronized void phasePlotMode() {
init();
mediator.changeAnalysisType(AnalysisType.PHASE_PLOT);
mediator.waitForJobCompletion();
}
/**
* Switch to phase raw (light curve) mode.
*/
public synchronized void lightCurveMode() {
init();
mediator.changeAnalysisType(AnalysisType.RAW_DATA);
mediator.waitForJobCompletion();
}
/**
* Create a phase plot given period and epoch.
*
* @param period The period on which to fold the data.
* @param epoch The epoch (first Julian Date) for the phase plot.
*/
public synchronized void phasePlot(double period, double epoch) {
init();
mediator.createPhasePlot(period, epoch);
mediator.waitForJobCompletion();
}
/**
* Create a polynomial fit model given the specified series and polynomial
* degree.
*
* @param seriesName Name of series to which polynomial fit should be applied.
*
* @param degree The required polynomial degree.
*/
public synchronized void polyfit(String seriesName, double degree) {
modelCreatorCommon(null, ApacheCommonsPolynomialFitCreatorPlugin.class, seriesName, new Double[] { degree });
}
/**
* Create a model given the specified partial plugin name, series and
* parameters.
*
* @param seriesName Name of series to which the model creation operation should
* be applied.
* @param params Array of parameters; could be of any type.
*/
public synchronized void createModel(String pluginName, String seriesName, Object[] params) {
modelCreatorCommon(pluginName, null, seriesName, params);
}
/**
* Perform DCDFT period analysis with period range.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @param lowPeriod The low value of the period range to search in.
* @param highPeriod The high value of the period range to search in.
* @param resolution The resolution of the search over the range.
* @return An array of top-hits periods.
*/
public synchronized Double[] dcdftPeriod(String seriesName, double lowPeriod, double highPeriod,
double resolution) {
return dcdftCommon(seriesName, DcDftAnalysisType.PERIOD_RANGE, lowPeriod, highPeriod, resolution);
}
/**
* Perform DCDFT period analysis with frequency range.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @param lowFrequency The low value of the frequency range to search in.
* @param highPeriod The high value of the frequency range to search in.
* @param resolution The resolution of the search over the range.
* @return An array of top-hits frequencies.
*/
public synchronized Double[] dcdftFrequency(String seriesName, double lowFrequency, double highFrequency,
double resolution) {
return dcdftCommon(seriesName, DcDftAnalysisType.FREQUENCY_RANGE, lowFrequency, highFrequency, resolution);
}
/**
* Perform DCDFT period analysis with standard scan.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @return An array of top-hits frequencies.
*/
public synchronized Double[] dcdftStandardScan(String seriesName) {
return dcdftCommon(seriesName, DcDftAnalysisType.STANDARD_SCAN, 0, 0, 0);
}
/**
* Perform WWZ time-frequency analysis with period range.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @param minPeriod The low value of the period range to search in.
* @param maxPeriod The high value of the period range to search in.
* @param periodStep The resolution of the search over the range.
* @param decay The wavelet decay constant to use.
* @param timeDivisions The number of time divisions to use.
* @return An array of top-hits periods; may be empty.
*/
public synchronized Double[][] wwzPeriod(String seriesName, double minPeriod, double maxPeriod, double periodStep,
double decay, double timeDivisions) {
List<ValidObservation> obs = getObsForSeries(seriesName);
Double[][] results = {};
if (obs.size() > 0) {
WeightedWaveletZTransform wwz = new WeightedWaveletZTransform(obs, decay, timeDivisions);
wwz.make_freqs_from_period_range(Math.min(minPeriod, maxPeriod), Math.max(minPeriod, maxPeriod),
periodStep);
results = wwzCommon(wwz, WWZCoordinateType.PERIOD);
}
return results;
}
/**
* Perform WWZ time-frequency analysis with period range.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @param minFreq The low value of the frequency range to search in.
* @param maxFreq The high value of the frequency range to search in.
* @param freqStep The resolution of the search over the range.
* @param decay The wavelet decay constant to use.
* @param timeDivisions The number of time divisions to use.
* @return An array of top-hits frequencies; may be empty.
*/
public synchronized Double[][] wwzFrequency(String seriesName, double minFreq, double maxFreq, double freqStep,
double decay, double timeDivisions) {
List<ValidObservation> obs = getObsForSeries(seriesName);
Double[][] results = {};
if (obs.size() > 0) {
WeightedWaveletZTransform wwz = new WeightedWaveletZTransform(obs, decay, timeDivisions);
wwz.make_freqs_from_freq_range(Math.min(minFreq, maxFreq), Math.max(minFreq, maxFreq), freqStep);
results = wwzCommon(wwz, WWZCoordinateType.FREQUENCY);
}
return results;
}
/**
* Return the last error.
*
* @return The error string; may be null.
*/
public synchronized String getError() {
return ScriptRunner.getInstance().getError();
}
/**
* Return the last warning.
*
* @return The warning string; may be null.
*/
public synchronized String getWarning() {
return ScriptRunner.getInstance().getWarning();
}
/**
* Returns a comma-separated string of series names for the current dataset,
* including bands and synthetic series such as means, model, residuals.
*
* @return a comma-separated series names
*/
public synchronized String getSeries() {
init();
ObservationAndMeanPlotModel model = analysisTypeMsg.getObsAndMeanChartPane().getObsModel();
String nameStr = "";
for (SeriesType type : model.getSeriesKeys()) {
nameStr += type.getShortName() + ",";
}
if (nameStr.lastIndexOf(",") != -1) {
nameStr = nameStr.substring(0, nameStr.lastIndexOf(","));
}
return nameStr;
}
/**
* Returns the time values (e.g. JD, HJD) for the specified series.
*
* @param seriesName The short or long series name.
* @return An array of time values.
*/
public double[] getTimes(String seriesName) {
List<ValidObservation> obs = getObsForSeries(seriesName);
List<Double> timeList = obs.stream().map(ob -> ob.getJD()).collect(Collectors.toList());
double[] times = new double[timeList.size()];
int i = 0;
for (Double time : timeList) {
times[i++] = time;
}
return times;
}
/**
* Returns the (standard) phase values for the specified series.
*
* @param seriesName The short or long series name.
* @return An array of phase values.
*/
public double[] getPhases(String seriesName) {
List<ValidObservation> obs = getObsForSeries(seriesName);
List<Double> phaseList = obs.stream().map(ob -> ob.getStandardPhase()).collect(Collectors.toList());
double[] phases = new double[phaseList.size()];
int i = 0;
for (Double phase : phaseList) {
phases[i++] = phase;
}
return phases;
}
/**
* Returns the magnitude values for the specified series.
*
* @param seriesName The short or long series name.
* @return An array of magnitude values.
*/
public double[] getMags(String seriesName) {
List<ValidObservation> obs = getObsForSeries(seriesName);
List<Double> magList = obs.stream().map(ob -> ob.getMag()).collect(Collectors.toList());
double[] mags = new double[magList.size()];
int i = 0;
for (Double mag : magList) {
mags[i++] = mag;
}
return mags;
}
/**
* Makes the specified series in the current dataset visible. Calling this
* method more than one consecutive time with the same visibility value has no
* effect on the current visibility status of a series.
*
* @param seriesName The long name (e.g. "Johnson V" not "V") of the series to
* make visible.
*/
public synchronized void makeVisible(final String seriesName) {
init();
ObservationAndMeanPlotModel obsPlotModel = analysisTypeMsg.getObsAndMeanChartPane().getObsModel();
if (SeriesType.exists(seriesName)) {
SeriesType series = SeriesType.getSeriesFromDescription(seriesName);
if (obsPlotModel.getSeriesKeys().contains(series)) {
int seriesNum = obsPlotModel.getSrcTypeToSeriesNumMap().get(series);
obsPlotModel.changeSeriesVisibility(seriesNum, true);
} else {
ScriptRunner.getInstance().setError("Series does not exist in loaded dataset: " + seriesName);
}
} else {
ScriptRunner.getInstance().setError("Unknown series type: " + seriesName);
}
mediator.waitForJobCompletion();
}
// TODO:
// - makeInvisible()
// - allow AoV, other period search plugins: see
// commonLoadFromFileOrURLViaPlugin() re: pattern;
// API may need to change to accommodate this, e.g.
// a generic way to get results as a collection
/**
* Create a scatter plot in the named tab.
*
* @param name The name of the dataset to create or add to.
* @param xTitle The x axis title.
* @param yTitle The y axis title.
* @param xs The x values to plot.
* @param ys The y values to plot.
*/
public synchronized void scatter(String name, String xTitle, String yTitle, double[] xs, double[] ys) {
// TODO: in a future revision, store/get dataset in/from DocumentManager and
// fire dataset change if exists when adding new series; also need plot if e.g.
// scatter then lines(); also setting renderer for dataset
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries series = new XYSeries(name);
for (int i = 0; i < xs.length; i++) {
series.add(xs[i], ys[i]);
}
dataset.addSeries(series);
JFreeChart chart = ChartFactory.createScatterPlot(name, xTitle, yTitle, dataset, PlotOrientation.VERTICAL, true,
true, true);
XYPlot plot = (XYPlot) chart.getPlot();
plot.setBackgroundPaint(new Color(255, 255, 255));
ChartPanel panel = new ChartPanel(chart);
Mediator.getUI().addTab(name, ViewModeType.PLOT_OBS_MODE, panel, false);
}
/**
* Pause for the specified number of milliseconds.
*
* @param millis The time to pause for.
*/
public synchronized void pause(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
}
}
/**
* Exit VStar
*/
public synchronized void exit() {
mediator.quit();
}
// *************************************
// ** VStar scripting API methods end **
// *************************************
// Common methods
/**
* Common dataset file load method.
*
* @param path The path to the file or URL.
* @param isAdditive Is this load additive?
*/
private void commonLoadFromFile(final String path, boolean isAdditive) {
init();
commonLoadFromFileOrURLViaPlugin(MenuBar.NEW_STAR_FROM_FILE, InputType.FILE, path, isAdditive);
}
/**
* Common dataset URL load method.
*
* @param url The URL of the file.
* @param isAdditive Is this load additive?
*/
private void commonLoadFromURL(final String url, boolean isAdditive) {
init();
commonLoadFromFileOrURLViaPlugin(MenuBar.NEW_STAR_FROM_FILE, InputType.URL, url, isAdditive);
}
/**
* Common dataset plug-in load method.
*
* @param pluginName The sub-string with which to match the plug-in name.
* @param inputType The input type (e.g. file, URL).
* @param location The path or URL to the file.
* @param isAdditive Is this load additive?
*/
private void commonLoadFromFileOrURLViaPlugin(final String pluginName, InputType inputType, final String location,
boolean isAdditive) {
init();
ObservationSourcePluginBase obSourcePlugin = null;
for (ObservationSourcePluginBase plugin : PluginLoader.getObservationSourcePlugins()) {
if (plugin.getDisplayName().contains(pluginName)
&& (plugin.getInputType() == inputType || plugin.getInputType() == InputType.FILE_OR_URL)) {
obSourcePlugin = plugin;
break;
}
}
if (obSourcePlugin != null) {
try {
if (inputType == InputType.FILE) {
mediator.createObservationArtefactsFromObSourcePlugin(obSourcePlugin, new File(location),
isAdditive);
} else if (inputType == InputType.URL) {
mediator.createObservationArtefactsFromObSourcePlugin(obSourcePlugin, new URL(location),
isAdditive);
}
} catch (IOException e) {
MessageBox.showErrorDialog("Load File", "Cannot load file: " + location);
} catch (ObservationReadError e) {
MessageBox.showErrorDialog("Load File", "Error reading observations from file: " + location
+ " (reason: " + e.getLocalizedMessage() + ")");
}
} else {
MessageBox.showErrorDialog("Load File", "No matching observation plugin found '" + pluginName + "'");
}
mediator.waitForJobCompletion();
}
/**
* Common AID dataset load method.
*
* @param name The target name (not AUID).
* @param minJD The minimum JD of the range to be loaded.
* @param maxJD The maximum JD of the range to be loaded.
* @param band A comma-delimited list of short band names or null for all
* available bands.
* @oaram obscodes A comma-delimited list of observer codes or null for all
* available observer codes.
* @param loadMinimalFields Load a minimal field subset?
* @param isAdditive Is this load additive?
*/
private void commonLoadFromAID(final String name, double minJD, double maxJD, String bands, String obscodes,
boolean loadMinimalFields, boolean isAdditive) {
init();
ObservationSourcePluginBase obSourcePlugin = null;
for (ObservationSourcePluginBase plugin : PluginLoader.getObservationSourcePlugins()) {
if (plugin.getDisplayName().contains(MenuBar.NEW_STAR_FROM_DATABASE)) {
obSourcePlugin = plugin;
break;
}
}
if (obSourcePlugin != null) {
try {
VSXWebServiceStarInfoSource infoSrc = new VSXWebServiceStarInfoSource();
StarInfo info = infoSrc.getStarByName(name);
String url = "";
AIDWebServiceObservationSourcePluginBase aidPlugin = (AIDWebServiceObservationSourcePluginBase) obSourcePlugin;
if (bands == null) {
url = aidPlugin.createAIDUrlForAUID(info.getAuid(), minJD, maxJD);
} else {
// TODO: change null and false to use parameters passed in
url = aidPlugin.createAIDUrlForAUID(info.getAuid(), minJD, maxJD, bands, null, false);
}
aidPlugin.setUrl(url);
aidPlugin.setInfo(info);
mediator.createObservationArtefactsFromObSourcePlugin(aidPlugin, (URL) null, isAdditive);
} catch (IOException e) {
MessageBox.showErrorDialog("Load from AID", "Cannot load from AID: " + name);
} catch (ObservationReadError e) {
MessageBox.showErrorDialog("Load from AID",
"Error reading observations from AID: " + name + " (reason: " + e.getLocalizedMessage() + ")");
}
} else {
MessageBox.showErrorDialog("Load from AID", "Error initialising load from AID plug-in");
}
mediator.waitForJobCompletion();
}
/**
*
* @param pluginName
* @return
*/
private ObservationSinkPluginBase getObsSinkPlugin(String pluginName) {
ObservationSinkPluginBase obSinkPlugin = null;
for (ObservationSinkPluginBase plugin : PluginLoader.getObservationSinkPlugins()) {
if (plugin.getDisplayName().contains(pluginName)) {
obSinkPlugin = plugin;
break;
}
}
return obSinkPlugin;
}
/**
* Perform DCDFT period analysis.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @param analysisType Period range, frequency range, standard scan?
* @param lowPeriod The low value of the period range to search in.
* @param highPeriod The high value of the period range to search in.
* @param resolution The resolution of the search over the range.
* @return An array of top-hits periods or frequencies.
*/
private synchronized Double[] dcdftCommon(String seriesName, DcDftAnalysisType analysisType, double low,
double high, double resolution) {
init();
Double[] topHitPeriods = null;
List<ValidObservation> obs = getObsForSeries(seriesName);
if (obs.size() > 0) {
TSDcDft dcdft = null;
switch (analysisType) {
case PERIOD_RANGE:
dcdft = new TSDcDft(obs, DcDftAnalysisType.PERIOD_RANGE);
dcdft.setLoPeriodValue(low);
dcdft.setHiPeriodValue(high);
dcdft.setResolutionValue(resolution);
break;
case FREQUENCY_RANGE:
dcdft = new TSDcDft(obs, low, high, resolution);
break;
case STANDARD_SCAN:
dcdft = new TSDcDft(obs);
break;
}
try {
dcdft.execute();
Map<PeriodAnalysisCoordinateType, List<Double>> topHits = dcdft.getTopHits();
PeriodAnalysisCoordinateType coordType = null;
if (analysisType == DcDftAnalysisType.PERIOD_RANGE) {
coordType = PeriodAnalysisCoordinateType.PERIOD;
} else {
coordType = PeriodAnalysisCoordinateType.FREQUENCY;
}
// Get array of top-hit periods or frequencies.
topHitPeriods = topHits.get(coordType).toArray(new Double[0]);
} catch (AlgorithmError e) {
ScriptRunner.getInstance().setError(e.getMessage());
}
} else {
ScriptRunner.getInstance().setError("No observations in series " + seriesName);
}
return topHitPeriods;
}
/**
* Perform WWZ period analysis.
*
* @param wwz The initialised (WWZ transform object.
* @param coordType The coordinate type: period or frequency.
* @return An array of top-hits times and periods or frequencies.
*/
private synchronized Double[][] wwzCommon(WeightedWaveletZTransform wwz, WWZCoordinateType coordType) {
init();
Double[][] maximalStats = null;
try {
wwz.execute();
List<WWZStatistic> maximalStatsList = wwz.getMaximalStats();
maximalStats = new Double[maximalStatsList.size()][2];
int i = 0;
for (WWZStatistic stat : maximalStatsList) {
Double[] pair = new Double[2];
pair[0] = stat.getTau();
switch (coordType) {
case FREQUENCY:
pair[1] = stat.getFrequency();
break;
case PERIOD:
pair[1] = stat.getPeriod();
break;
default:
throw new IllegalArgumentException("WWZ: only period or frequency allowed in output");
}
maximalStats[i++] = pair;
}
} catch (AlgorithmError e) {
ScriptRunner.getInstance().setError(e.getMessage());
}
return maximalStats;
}
/**
* Common model creator plugin method.
*
* @param seriesName Partial plugin name; may be null.
* @param clazz Plugin class; may be null.
* @param series Name of series to which the model creation operation should
* be applied.
* @param params Array of parameters; could be of any type.
*/
private void modelCreatorCommon(String pluginName, Class<?> clazz, String seriesName, Object[] params) {
// It's not okay for them both to be null!
assert pluginName != null || clazz != null;
for (ModelCreatorPluginBase plugin : PluginLoader.getModelCreatorPlugins()) {
if ((pluginName != null && plugin.getDisplayName().contains(pluginName))
|| (clazz != null && plugin.getClass() == clazz)) {
plugin.setParams(params);
List<ValidObservation> obs = getObsForSeries(seriesName);
IModel model = plugin.getModel(obs);
Mediator.getInstance().performModellingOperation(model);
mediator.waitForJobCompletion();
break;
}
}
}
/**
* Given a series name, return a list of observations for the series.
*
* @param seriesName The short or long form of the series name, e.g. V or
* Johnson V.
* @return A list of valid observations for the series; may be empty.
*/
private List<ValidObservation> getObsForSeries(String seriesName) {
List<ValidObservation> obs = Collections.emptyList();
// Find the requested series...
SeriesType series = SeriesType.getSeriesFromShortName(seriesName);
if (series == SeriesType.getDefault()) {
series = SeriesType.getSeriesFromDescription(seriesName);
}
// ...if the user wasn't really asking for the default series name but
// we got it anyway, we treat this as an error.
if (series == SeriesType.getDefault()
&& !SeriesType.getDefault().getDescription().equals(seriesName.toLowerCase())) {
ScriptRunner.getInstance().setError("Unknown series " + seriesName);
} else {
// ...otherwise, get the observations for the requested series.
obs = mediator.getObservationPlotModel(mediator.getAnalysisType()).getObservations(series);
if (obs.size() == 0) {
ScriptRunner.getInstance().setError("No observations in series " + seriesName);
}
}
return obs;
}
// Helpers
private void init() {
clearError();
}
private void clearError() {
ScriptRunner.getInstance().setError(null);
}
}