Java tutorial
/** * Abstract class to encapsulate processes for analyzing and optimizing instrument models. * * Copyright (C) 2014, Edward Kort, Antoine Lefebvre, Burton Patkau. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.wwidesigner.gui; import java.awt.Frame; import java.io.File; import java.io.StringWriter; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.prefs.Preferences; import org.apache.commons.math3.exception.ZeroException; import com.jidesoft.app.framework.BasicDataModel; import com.jidesoft.app.framework.file.FileDataModel; import com.jidesoft.app.framework.gui.DataViewPane; import com.wwidesigner.geometry.Instrument; import com.wwidesigner.geometry.bind.GeometryBindFactory; import com.wwidesigner.geometry.view.InstrumentComparisonTable; import com.wwidesigner.gui.util.DataOpenException; import com.wwidesigner.gui.util.HoleNumberMismatchException; import com.wwidesigner.gui.util.OptimizerMismatchException; import com.wwidesigner.modelling.InstrumentCalculator; import com.wwidesigner.modelling.InstrumentTuner; import com.wwidesigner.modelling.PlayingRangeSpectrum; import com.wwidesigner.modelling.SupplementaryInfoTable; import com.wwidesigner.note.Fingering; import com.wwidesigner.note.Tuning; import com.wwidesigner.note.bind.NoteBindFactory; import com.wwidesigner.optimization.BaseObjectiveFunction; import com.wwidesigner.optimization.Constraints; import com.wwidesigner.optimization.ObjectiveFunctionOptimizer; import com.wwidesigner.optimization.bind.OptimizationBindFactory; import com.wwidesigner.util.BindFactory; import com.wwidesigner.util.Constants.LengthType; import com.wwidesigner.util.PhysicalParameters; /** * Abstract class to encapsulate processes for analyzing and optimizing * instrument models. * * @author kort * */ public abstract class StudyModel implements CategoryType { // Parameters for plotting impedance spectrum. // Plot from a major 9th below to 3rd harmonic above. protected static final double SPECTRUM_FREQUENCY_BELOW = 0.45; protected static final double SPECTRUM_FREQUENCY_ABOVE = 3.17; protected static final int SPECTRUM_NUMBER_OF_POINTS = 2000; // Number of // points to // plot. // Preferences. protected BaseObjectiveFunction.OptimizerType preferredOptimizerType; // Optimization currently active in optimizeInstrument(). // null if not executing optimizeInstrument. protected BaseObjectiveFunction objective; // Statistics saved from the most recent call to optimizeInstrument protected double initialNorm; // Initial value of objective function. protected double finalNorm; // Final value of objective function. /** * Tree of selectable categories that the study model supports. */ protected List<Category> categories; /** * Map of the default ContainedXmlView for each viewable category. */ protected Map<String, Class<? extends ContainedXmlView>> defaultXmlViewMap; /** * For each viewable category, the list of ContainedXmlViews that will be * displayed. */ protected Map<String, Class<ContainedXmlView>[]> toggleXmlViewLists; /** * Physical parameters to use for this study model. */ protected PhysicalParameters params; public StudyModel() { setCategories(); preferredOptimizerType = null; objective = null; } protected void setCategories() { categories = new ArrayList<Category>(); categories.add(new Category(INSTRUMENT_CATEGORY_ID)); categories.add(new Category(TUNING_CATEGORY_ID)); setDefaultViewClassMap(); setToggleViewClassesMap(); } /** * @return List of names of the categories in this study model. */ public List<String> getCategoryNames() { List<String> names = new ArrayList<String>(); for (Category thisCategory : categories) { names.add(thisCategory.name); } return names; } /** * @param Name * of category to retrieve. * @return The named category, or null if named category not found. */ protected Category getCategory(String name) { Category category = null; for (Category thisCategory : categories) { if (thisCategory.toString().equals(name)) { category = thisCategory; break; } } return category; } /** * Find the index in the Categories list of a named category. * * @param name * The category name to be found * @return The index of the found category, null otherwise. */ protected Integer getCategoryIndex(String name) { Integer index = null; int intIndex = 0; for (Category thisCategory : categories) { if (thisCategory.toString().equals(name)) { index = intIndex; break; } intIndex++; } return index; } /** * @param categoryName * - Name of category to select. * @param subcategoryName * - Name of subcategory to select in the named category. Post: * getSelectedSub(categoryName) returns subCategoryName. */ public void setCategorySelection(String categoryName, String subcategoryName) { for (Category thisCategory : categories) { if (thisCategory.name.equals(categoryName)) { thisCategory.setSelectedSub(subcategoryName); } } } /** * @param categoryName * - Name of category to look up. * @return Set of names of subcategories of the named category. */ public Set<String> getSubcategories(String categoryName) { for (Category thisCategory : categories) { if (thisCategory.name.equals(categoryName)) { return thisCategory.getSubs().keySet(); } } return new HashSet<String>(); } /** * @param categoryName * - Name of category to look up. * @return Subcategory name supplied to setCategorySelection(categoryName, * subcategoryName). */ public String getSelectedSub(String categoryName) { for (Category thisCategory : categories) { if (thisCategory.name.equals(categoryName)) { return thisCategory.getSelectedSub(); } } return ""; } /** * Determines whether a subcategory is found under a category, either by * subcategory name or value. * * @param categoryId * The category ID to be searched. * @param subCategory * Either the name or value of the subcategory * @param useName * If true, use the subcategory name, otherwise the value. * @return True if the subcategory is found. */ protected boolean isValidSubCategory(String categoryId, Object subCategory, boolean useName) { Category category = getCategory(categoryId); if (category == null) { return false; } return isSubFound(category, subCategory, useName); } protected boolean isSubFound(Category category, Object subCategory, boolean useName) { Map<String, Object> subs = category.getSubs(); for (String key : subs.keySet()) { if (useName) { if (key.equals(subCategory)) { return true; } } else if (subs.get(key).equals(subCategory)) { return true; } } return false; } /** * Class to encapsulate a main branch of the study model selection tree. The * derived study model defines a set of main branches, typically a static * set. */ protected static class Category { private String name; private Map<String, Object> subs; private String selectedSub; private Map<String, String> toolTips = new HashMap<String, String>(); public Category(String name) { this.name = name; } public String toString() { return name; } public void addSub(String name, Object sub) { if (subs == null) { subs = new TreeMap<String, Object>(); } subs.put(name, sub); } public void addSub(String name, Object sub, String toolTip) { addSub(name, sub); toolTips.put(name, toolTip); } public void removeSub(String name) { if (name.equals(selectedSub)) { selectedSub = null; } subs.remove(name); toolTips.remove(name); } public void removeSubByValue(Object value) { int size = subs.size(); if (value == null) { return; } if (value.equals(getSelectedSubValue())) { selectedSub = null; } Iterator<Entry<String, Object>> iterator = subs.entrySet().iterator(); while (iterator.hasNext()) { Entry<String, Object> entry = iterator.next(); if (value.equals(entry.getValue())) { iterator.remove(); toolTips.remove(entry.getKey()); if (size != 2) { break; } } else if (size == 2) { // If there's only one other entry, select it. selectedSub = entry.getKey(); } } } public Map<String, Object> getSubs() { if (subs == null) { subs = new TreeMap<String, Object>(); } return subs; } public Map<String, String> getToolTips() { return toolTips; } public void setSelectedSub(String key) { selectedSub = key; } public String getSelectedSub() { return selectedSub; } public Object getSelectedSubValue() { if (subs == null || selectedSub == null) { return null; } return subs.get(selectedSub); } /** * Replaces a subcategory entry because of a name change: save as or * rename * * @param newName * New subcategory name * @param source * DataModel value of the subcategory * @return True if a successful replacement was performed, false * otherwise */ public boolean replaceSub(String newName, FileDataModel source) { // Find sub by matching dataModel reference String oldName = null; boolean isSelected = false; if (subs == null) { return false; } for (Map.Entry<String, Object> entry : subs.entrySet()) { FileDataModel model = (FileDataModel) entry.getValue(); if (source.equals(model)) { oldName = entry.getKey(); break; } } if (oldName != null) { if (oldName.equals(selectedSub)) { isSelected = true; } removeSub(oldName); } else { return false; } addSub(newName, source); if (isSelected) { setSelectedSub(newName); } return true; } } /** * @param xmlString * - XML defining an Instrument or a Tuning. * @return Name of category that the definition of xmlString fits, either * INSTRUMENT_CATEGORY_ID or TUNING_CATEGORY_ID. */ public static String getCategoryName(String xmlString) { // Check for an Instrument BindFactory bindFactory = GeometryBindFactory.getInstance(); if (bindFactory.isValidXml(xmlString, "Instrument", true)) // TODO Make // constants // in // binding // framework { return INSTRUMENT_CATEGORY_ID; } // Check for a Tuning bindFactory = NoteBindFactory.getInstance(); if (bindFactory.isValidXml(xmlString, "Tuning", true)) // TODO Make // constants in // binding // framework { return TUNING_CATEGORY_ID; } // Check for a Constraints bindFactory = OptimizationBindFactory.getInstance(); if (bindFactory.isValidXml(xmlString, "Constraints", true)) // TODO Make // constants in // binding // framework { return CONSTRAINTS_CATEGORY_ID; } return null; } protected Integer getNumberOfHolesFromInstrument() { try { return getHoleCountFromSelected(INSTRUMENT_CATEGORY_ID); } catch (Exception e) { } return null; } /** * Replaces a Category in the categories list. * * @param categoryId * Category ID * @param replacementCategory */ protected void replaceCategory(String categoryId, Category replacementCategory) { int categoryIndex = getCategoryIndex(CONSTRAINTS_CATEGORY_ID); categories.set(categoryIndex, replacementCategory); } /** * Add an Instrument or Tuning to the category tree, from a JIDE * FileDataModel. Post: If dataModel is valid XML, it is added to * INSTRUMENT_CATEGORY_ID, or TUNING_CATEGORY_ID, as appropriate, and * addDataModel returns true. * * @param dataModel * - FileDataModel containing instrument or tuning XML. * @return true iff the dataModel contained valid instrument or tuning XML. */ public boolean addDataModel(FileDataModel dataModel, boolean isNew) throws Exception { String data = (String) dataModel.getData().toString(); if (data == null || data.length() == 0) { return false; } String categoryName = getCategoryName(data); if (categoryName == null) { throw new DataOpenException("Data is not a supported type", DataOpenException.DATA_TYPE_NOT_SUPPORTED); } dataModel.setSemanticName(categoryName); if (categoryName.equals(INSTRUMENT_CATEGORY_ID) || categoryName.equals(TUNING_CATEGORY_ID)) { Category category = getCategory(categoryName); category.addSub(dataModel.getName(), dataModel); category.setSelectedSub(dataModel.getName()); if (!isNew) { validHoleCount(); } return true; } return false; } /** * Remove an Instrument or Tuning from the category tree, given a JIDE * FileDataModel. Pre: Assumes that the type of XML, Instrument or Tuning, * has not changed since the call to addDataModel. Post: The specified * dataModel is no longer in INSTRUMENT_CATEGORY_ID, or TUNING_CATEGORY_ID, * as appropriate. * * @param dataModel * - FileDataModel containing instrument or tuning XML. * @return true. */ public boolean removeDataModel(FileDataModel dataModel) { String data = (String) dataModel.getData(); String categoryName = getCategoryName(data); Category category; if (categoryName == null) { // Invalid XML. Remove from both categories. category = getCategory(INSTRUMENT_CATEGORY_ID); category.removeSubByValue(dataModel); category = getCategory(TUNING_CATEGORY_ID); category.removeSubByValue(dataModel); return true; } category = getCategory(categoryName); category.removeSubByValue(dataModel); return true; } /** * Add an Instrument or Tuning to the category tree, from a JIDE * FileDataModel, replacing any existing instance. Pre: Assumes that the * type of XML, Instrument or Tuning, has not changed since the call to * addDataModel (if any). Post: The prior instance of dataModel is removed * from INSTRUMENT_CATEGORY_ID, or TUNING_CATEGORY_ID, as appropriate If * dataModel is valid XML, it is added to INSTRUMENT_CATEGORY_ID, or * TUNING_CATEGORY_ID, as appropriate, and addDataModel returns true. * * @param dataModel * - FileDataModel containing instrument or tuning XML. * @return true if the dataModel contained valid instrument or tuning XML. */ public boolean replaceDataModel(FileDataModel dataModel) throws DataOpenException { String data = (String) dataModel.getData(); String categoryName = getCategoryName(data); if (categoryName == null) { removeDataModel(dataModel); throw new DataOpenException("Data does not represent a supported type.", DataOpenException.DATA_TYPE_NOT_SUPPORTED); } Category category = getCategory(categoryName); if (category.replaceSub(dataModel.getName(), dataModel)) { category.setSelectedSub(dataModel.getName()); return true; } return false; } /** * @return true if category selections are sufficient for calls to * calculateTuning() and graphTuning(). */ public boolean canTune() { boolean canTune = false; try { canTune = validHoleCount(); } catch (Exception e) { } return canTune; } protected boolean validHoleCount() throws Exception { Integer tuningHoleCount = getHoleCountFromSelected(TUNING_CATEGORY_ID); Integer instrumentHoleCount = getHoleCountFromSelected(INSTRUMENT_CATEGORY_ID); if (tuningHoleCount == null || instrumentHoleCount == null) { return false; } if (tuningHoleCount == instrumentHoleCount) { return true; } throw new HoleNumberMismatchException( "Tuning file has " + tuningHoleCount + " holes, Instrument has " + instrumentHoleCount + " holes."); } /** * Gets the hole count from the selected data of the specified data type. * * @param categoryId * One of CONSTRAINTS_CATEGORY_ID, INSTRUMENT_CATEGORY_ID, or * TUNING_CATEGORY_ID * @return The hole count, null if the specified data type does not have a * selected value * @throws Exception * On data parse error */ protected Integer getHoleCountFromSelected(String categoryId) throws Exception { Integer holeCount = null; if (TUNING_CATEGORY_ID.equals(categoryId)) { Category tuningCategory = getCategory(TUNING_CATEGORY_ID); String tuningSelected = tuningCategory.getSelectedSub(); if (tuningSelected != null) { Tuning tuning = getTuning(); holeCount = tuning.getNumberOfHoles(); } } else if (INSTRUMENT_CATEGORY_ID.equals(categoryId)) { Category instrumentCategory = getCategory(INSTRUMENT_CATEGORY_ID); String instrumentSelected = instrumentCategory.getSelectedSub(); if (instrumentSelected != null) { Instrument instrument = getInstrument(); // Don't bother checking instrument validity. holeCount = instrument.getHole().size(); } } else if (CONSTRAINTS_CATEGORY_ID.equals(categoryId)) { Category constraintsCategory = getCategory(CONSTRAINTS_CATEGORY_ID); String constraintsSelected = constraintsCategory.getSelectedSub(); if (constraintsSelected != null) { Constraints constraints = getConstraints(); holeCount = constraints.getNumberOfHoles(); } } return holeCount; } /** * @return true if category selections are sufficient for calls to * optimizeInstrument(). */ public boolean canOptimize() { if (!canTune()) { return false; } Category category = getCategory(OPTIMIZER_CATEGORY_ID); String optimizerSelected = category.getSelectedSub(); return optimizerSelected != null; } /** * A stub to update/change the Constraints Category upon selection changes * in the other Category selections. Should be overridden in subclasses that * need this functionality. */ public void updateConstraints() { } /** * A stub to build up the current path to Constraints. Should be overridden * in subclasses that need this functionality. * * @param rootDirectoryPath * Root of all the constraints. May be blank, but not null. * @return The File representing the leaf directory. May be null if not * overridden. */ public File getConstraintsLeafDirectory(String rootDirectoryPath) { return null; } public File getConstraintsLeafDirectory(String rootDirectoryPath, Constraints constraints) { return null; } /** * A stub to set the Constraint menu items active. Overwrite in subclasses. * * @param constraintsDirectory * The root of the constraints directory tree. * @return */ public boolean isOptimizerFullySpecified(String constraintsDirectory) { return isOptimizerConstraintsDirectorySpecified(constraintsDirectory) && isOptimizerCreateSpecified(); } public boolean isOptimizerConstraintsDirectorySpecified(String constraintsDirectory) { if (constraintsDirectory == null || constraintsDirectory.trim().length() == 0) { return false; } return true; } public boolean isOptimizerCreateSpecified() { boolean isSpecified; Integer dataNumberOfHoles = getNumberOfHolesFromInstrument(); String optimizerSelected = getSelectedSub(OPTIMIZER_CATEGORY_ID); // Constraints set is fully specified. isSpecified = dataNumberOfHoles != null && optimizerSelected != null; return isSpecified; } public void calculateTuning(String title) throws Exception { InstrumentTuner tuner = getInstrumentTuner(); Category category = this.getCategory(INSTRUMENT_CATEGORY_ID); String instrumentName = category.getSelectedSub(); tuner.setInstrument(getInstrument()); category = getCategory(TUNING_CATEGORY_ID); String tuningName = category.getSelectedSub(); tuner.setTuning(getTuning()); tuner.setCalculator(getCalculator()); tuner.showTuning(title + ": " + instrumentName + "/" + tuningName, false); } public void calculateSupplementaryInfo(String title) throws Exception { InstrumentTuner tuner = getInstrumentTuner(); Category category = this.getCategory(INSTRUMENT_CATEGORY_ID); String instrumentName = category.getSelectedSub(); tuner.setInstrument(getInstrument()); category = getCategory(TUNING_CATEGORY_ID); String tuningName = category.getSelectedSub(); tuner.setTuning(getTuning()); tuner.setCalculator(getCalculator()); SupplementaryInfoTable table = new SupplementaryInfoTable(title + ": " + instrumentName + "/" + tuningName); table.buildTable(tuner, false); table.showTable(false); } public void graphTuning(String title) throws Exception { InstrumentTuner tuner = getInstrumentTuner(); Category category = this.getCategory(INSTRUMENT_CATEGORY_ID); String instrumentName = category.getSelectedSub(); tuner.setInstrument(getInstrument()); category = getCategory(TUNING_CATEGORY_ID); String tuningName = category.getSelectedSub(); tuner.setTuning(getTuning()); tuner.setCalculator(getCalculator()); tuner.plotTuning(title + ": " + instrumentName + "/" + tuningName, false); } public void graphNote(Fingering fingering) throws Exception { Instrument instrument = getInstrument(); if (instrument.getHole().size() != fingering.getNumberOfHoles()) { throw new HoleNumberMismatchException("Tuning file has " + fingering.getNumberOfHoles() + " holes, Instrument has " + instrument.getHole().size() + " holes."); } InstrumentCalculator calculator = getCalculator(); calculator.setInstrument(instrument); PlayingRangeSpectrum spectrum = new PlayingRangeSpectrum(); spectrum.plot(calculator, fingering, SPECTRUM_FREQUENCY_BELOW, SPECTRUM_FREQUENCY_ABOVE, SPECTRUM_NUMBER_OF_POINTS, false); } public String getDefaultConstraints(Object... parentFrame) throws Exception { BaseObjectiveFunction objective = getObjectiveFunction(BaseObjectiveFunction.DEFAULT_CONSTRAINTS_INTENT); // For the case of a cancelled hole-grouping. if (objective == null) { return null; } Constraints constraints = objective.getConstraints(); constraints.setConstraintsName("Default"); String xmlConstraints = marshal(constraints); return xmlConstraints; } public String getBlankConstraints(Frame parentFrame) throws Exception { BaseObjectiveFunction objective = getObjectiveFunction(BaseObjectiveFunction.BLANK_CONSTRAINTS_INTENT); // For the case of a cancelled hole-grouping. if (objective == null) { return null; } Constraints constraints = objective.getConstraints(); constraints.setConstraintsName("Blank"); String xmlConstraints = marshal(constraints); return xmlConstraints; } /** * Optimize the currently-selected objective function * * @return XML string defining the optimized instrument, if optimization * succeeds, or {@code null} if optimization fails. */ public String optimizeInstrument() throws Exception { if (!validHoleCount()) { return null; } objective = getObjectiveFunction(BaseObjectiveFunction.OPTIMIZATION_INTENT); // Check to see whether there are 0 variables: an infinite loop // situation. if (objective.getNrDimensions() < 1) { throw new ZeroException(); } BaseObjectiveFunction.OptimizerType optimizerType = objective.getOptimizerType(); if (preferredOptimizerType != null && !optimizerType.equals(BaseObjectiveFunction.OptimizerType.BrentOptimizer)) { optimizerType = preferredOptimizerType; } if (!objective.isOptimizerMatch(optimizerType)) { throw new OptimizerMismatchException("Cannot run multi-start optimization with " + optimizerType); } initialNorm = 1.0; finalNorm = 1.0; if (ObjectiveFunctionOptimizer.optimizeObjectiveFunction(objective, optimizerType)) { Instrument instrument = objective.getInstrument(); // Convert back to the input unit-of-measure values instrument.convertToLengthType(); String xmlString = marshal(instrument); initialNorm = ObjectiveFunctionOptimizer.getInitialNorm(); finalNorm = ObjectiveFunctionOptimizer.getFinalNorm(); objective = null; return xmlString; } objective = null; return null; } // optimizeInstrument public void cancelOptimization() { if (objective != null) { objective.setCancel(true); } } public void compareInstrument(String newName, Instrument newInstrument, LengthType defaultLengthType) throws Exception { String oldName = getSelectedInstrumentName(); Instrument oldInstrument = getInstrument(); InstrumentComparisonTable table = getInstrumentComparisonTable("", defaultLengthType); table.buildTable(oldName, oldInstrument, newName, newInstrument); table.showTable(); } protected InstrumentComparisonTable getInstrumentComparisonTable(String title, LengthType defaultLengthType) { return new InstrumentComparisonTable(title, defaultLengthType); } public String getSelectedInstrumentName() { String name = ""; Category category = getCategory(INSTRUMENT_CATEGORY_ID); FileDataModel model = (FileDataModel) category.getSelectedSubValue(); if (model != null) { name = model.getName(); } return name; } public static String marshal(Instrument instrument) throws Exception { BindFactory binder = GeometryBindFactory.getInstance(); StringWriter writer = new StringWriter(); binder.marshalToXml(instrument, writer); return writer.toString(); } public static String marshal(Tuning tuning) throws Exception { BindFactory binder = NoteBindFactory.getInstance(); StringWriter writer = new StringWriter(); binder.marshalToXml(tuning, writer); return writer.toString(); } public static String marshal(Constraints constraints) throws Exception { BindFactory bindFactory = OptimizationBindFactory.getInstance(); StringWriter writer = new StringWriter(); bindFactory.marshalToXml(constraints, writer); return writer.toString(); } protected String getSelectedXmlString(String categoryName) throws Exception { Category category = getCategory(categoryName); FileDataModel model = (FileDataModel) category.getSelectedSubValue(); if (model == null) { return null; } if (model.getApplication() != null) { // If the file is a data view in an active application, // update the data in model with the latest from the application's // data view. model.getApplication().getDataView(model).updateModel(model); } return (String) model.getData(); } /** * Return the instrument currently selected in the study model. * * @return a valid Instrument * @throws Exception * if no valid instrument is selected. */ protected Instrument getInstrument() throws Exception { BindFactory geometryBindFactory = GeometryBindFactory.getInstance(); String xmlString = getSelectedXmlString(INSTRUMENT_CATEGORY_ID); Instrument instrument = (Instrument) geometryBindFactory.unmarshalXml(xmlString, true); instrument.checkValidity(); instrument.updateComponents(); return instrument; } /** * Extract an instrument from an XML string, if possible. The instrument is * not checked for validity. * * @param xmlString * - String containing XML for an instrument definition. * @return an Instrument, or null */ public static Instrument getInstrument(String xmlString) { try { BindFactory geometryBindFactory = GeometryBindFactory.getInstance(); Instrument instrument = (Instrument) geometryBindFactory.unmarshalXml(xmlString, true); instrument.updateComponents(); return instrument; } catch (Exception e) { return null; } } protected Tuning getTuning() throws Exception { BindFactory noteBindFactory = NoteBindFactory.getInstance(); String xmlString = getSelectedXmlString(TUNING_CATEGORY_ID); Tuning tuning = (Tuning) noteBindFactory.unmarshalXml(xmlString, true); tuning.checkValidity(); return tuning; } protected Constraints getConstraints() throws Exception { BindFactory constraintsBindFactory = OptimizationBindFactory.getInstance(); String xmlString = getSelectedXmlString(CONSTRAINTS_CATEGORY_ID); Constraints constraints = (Constraints) constraintsBindFactory.unmarshalXml(xmlString, true); constraints.setConstraintParent(); return constraints; } public static Instrument getInstrumentFromFile(String fileName) throws Exception { BindFactory geometryBindFactory = GeometryBindFactory.getInstance(); String inputPath = BindFactory.getPathFromName(fileName); File inputFile = new File(inputPath); Instrument instrument = (Instrument) geometryBindFactory.unmarshalXml(inputFile, true); instrument.updateComponents(); return instrument; } public static Tuning getTuning(String xmlString) { try { BindFactory noteBindFactory = NoteBindFactory.getInstance(); Tuning tuning = (Tuning) noteBindFactory.unmarshalXml(xmlString, true); return tuning; } catch (Exception e) { return null; } } public static Tuning getTuningFromFile(String fileName) throws Exception { BindFactory noteBindFactory = NoteBindFactory.getInstance(); String inputPath = BindFactory.getPathFromName(fileName); File inputFile = new File(inputPath); Tuning tuning = (Tuning) noteBindFactory.unmarshalXml(inputFile, true); return tuning; } public static Constraints getConstraints(String xmlString) { try { BindFactory constraintsBindFactory = OptimizationBindFactory.getInstance(); Constraints constraints = (Constraints) constraintsBindFactory.unmarshalXml(xmlString, true); constraints.setConstraintParent(); return constraints; } catch (Exception e) { return null; } } public PhysicalParameters getParams() { return params; } public void setParams(PhysicalParameters params) { this.params = params; } /** * Set study model preferences from application preferences. * * @param newPreferences */ public void setPreferences(Preferences newPreferences) { double currentTemperature = newPreferences.getDouble(OptimizationPreferences.TEMPERATURE_OPT, OptimizationPreferences.DEFAULT_TEMPERATURE); double currentPressure = newPreferences.getDouble(OptimizationPreferences.PRESSURE_OPT, OptimizationPreferences.DEFAULT_PRESSURE); int currentHumidity = newPreferences.getInt(OptimizationPreferences.HUMIDITY_OPT, OptimizationPreferences.DEFAULT_HUMIDITY); int currentCO2 = newPreferences.getInt(OptimizationPreferences.CO2_FRACTION_OPT, OptimizationPreferences.DEFAULT_CO2_FRACTION); double xCO2 = currentCO2 * 1.0e-6; getParams().setProperties(currentTemperature, currentPressure, currentHumidity, xCO2); getParams().printProperties(); String optimizerPreference = newPreferences.get(OptimizationPreferences.OPTIMIZER_TYPE_OPT, OptimizationPreferences.OPT_DEFAULT_NAME); if (optimizerPreference.contentEquals(OptimizationPreferences.OPT_DEFAULT_NAME)) { preferredOptimizerType = null; } else if (optimizerPreference.contentEquals(OptimizationPreferences.OPT_DIRECT_NAME)) { preferredOptimizerType = BaseObjectiveFunction.OptimizerType.DIRECTOptimizer; } else { preferredOptimizerType = null; } } // Methods to return statistics from an optimization. public double getInitialNorm() { return initialNorm; } public double getFinalNorm() { return finalNorm; } public double getResidualErrorRatio() { return finalNorm / initialNorm; } protected Class<? extends ContainedXmlView> getDefaultViewClass(String categoryName) { Class<? extends ContainedXmlView> defaultClass = defaultXmlViewMap.get(categoryName); defaultClass = defaultClass == null ? ContainedXmlTextView.class : defaultClass; return defaultClass; } protected Class<ContainedXmlView>[] getToggleViewClasses(String categoryName) { return toggleXmlViewLists.get(categoryName); } /** * Create the default view for and XML dataModel for each type represented * in the XML. * * @param dataModel * @return created ContainedXmlView */ public ContainedXmlView getDefaultXmlView(FileDataModel dataModel, DataViewPane parent) { String xmlData = (String) dataModel.getData().toString(); String categoryName = getCategoryName(xmlData); Class<? extends ContainedXmlView> defaultViewClass = getDefaultViewClass(categoryName); ContainedXmlView defaultView = null; try { Constructor<? extends ContainedXmlView> constr = defaultViewClass .getConstructor(new Class[] { DataViewPane.class }); defaultView = (ContainedXmlView) constr.newInstance(new Object[] { parent }); } catch (Exception e) { System.err.println(e.getMessage()); } return defaultView; } /** * Creates the next ContainedXmlView instance for a model that has multiple * views configured in getToggleViewClasses. The GUI logic only allows this * call to be made if there is a multiple of such views. * * @param dataModel * Used to derive the data type, a CATEGORY_ID * @param containedXmlView * Used to determine the next view * @param parent * Needed in the constructor of the new view instance * @return The new ContainedXmlView instance. May return the input * ContainedXmlView if there is a programming error. */ public ContainedXmlView getNextXmlView(BasicDataModel dataModel, ContainedXmlView containedXmlView, DataViewPane parent) { Class<? extends ContainedXmlView> currentViewClass = containedXmlView.getClass(); ContainedXmlView nextView = null; String xmlData = (String) dataModel.getData().toString(); String categoryName = getCategoryName(xmlData); Class<ContainedXmlView>[] toggleViews = getToggleViewClasses(categoryName); Class<ContainedXmlView> nextViewClass = null; int numberOfToggles = toggleViews == null ? 0 : toggleViews.length; if (numberOfToggles > 1) { for (int i = 0; i < numberOfToggles; i++) { Class<ContainedXmlView> toggleView = toggleViews[i]; if (toggleView.equals(currentViewClass)) { if (i == (numberOfToggles - 1)) { nextViewClass = toggleViews[0]; } else { nextViewClass = toggleViews[i + 1]; } break; } } // This should only happen if you change study models with open data // views if (nextViewClass == null) { nextViewClass = toggleViews[0]; } try { Constructor<ContainedXmlView> constr = nextViewClass .getConstructor(new Class[] { DataViewPane.class }); nextView = (ContainedXmlView) constr.newInstance(new Object[] { parent }); } catch (Exception e) { System.err.println(e.getMessage()); } } // Return the original view on error nextView = nextView == null ? containedXmlView : nextView; return nextView; } /** * Returns the number of alternative ContainedXmlViews configured for a * specific data type, a CATEGORY_ID, in the XML. * * @param dataModel * Used to determine the data type * @return The number of alternative views, 0 if there are none configured */ public int getNumberOfToggleViews(BasicDataModel dataModel) { String xmlData = (String) dataModel.getData().toString(); String categoryName = getCategoryName(xmlData); Class<ContainedXmlView>[] toggleViews = getToggleViewClasses(categoryName); int numberOfViews = 0; if (toggleViews != null) { numberOfViews = toggleViews.length; } return numberOfViews; } // Methods to create objects that will perform this study, // according to components that the user has selected. /** * Create the selected calculator, and set its physical parameters. * * @return created calculator. */ protected abstract InstrumentCalculator getCalculator(); /** * Create the instrument tuner appropriate for this study. * * @return created tuner. */ protected abstract InstrumentTuner getInstrumentTuner(); /** * Create the objective function to use for either the selected * optimization, to generate a blank Constraints, or to generate a default * Constraints. Set the physical parameters, and set any constraints that * the user has selected as appropriate for the objectiveFunctionIntent. * * @param objectiveFunctionIntent * Indicates the Constraints content the objectiveFunction will * create. * @return * @throws Exception */ protected abstract BaseObjectiveFunction getObjectiveFunction(int objectiveFunctionIntent) throws Exception; /** * Configures the array of allowed ContainedXmlView classes for each data * type, a CATEGORY_ID, in the XML. * * @return A Map in which the keys a the data types, and the values are * arrays of ContainedXmlView classes. */ protected abstract void setToggleViewClassesMap(); /** * Configures the default ContainedXmlView to be used for each supported * data type, a CATEGORY_ID, in the XML. * * @param categoryName * @return The Class of the default view. The base StudyModel uses * reflection to create the instance. */ protected abstract void setDefaultViewClassMap(); /** * * @return The name to be displayed in the StudyView title. */ public abstract String getDisplayName(); }