diff --git a/pom.xml b/pom.xml index a71c065..88351e3 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ kotik-coder PULsE - 1.93 + 1.93F PULsE Processing Unit for Laser flash Experiments diff --git a/src/main/java/pulse/AbstractData.java b/src/main/java/pulse/AbstractData.java index f1f5ab8..2f58d47 100644 --- a/src/main/java/pulse/AbstractData.java +++ b/src/main/java/pulse/AbstractData.java @@ -32,8 +32,8 @@ public abstract class AbstractData extends PropertyHolder { private int count; - private List time; - private List signal; + protected List time; + protected List signal; private String name; diff --git a/src/main/java/pulse/input/ExperimentalData.java b/src/main/java/pulse/input/ExperimentalData.java index 3b2e5bd..bbbb2e6 100644 --- a/src/main/java/pulse/input/ExperimentalData.java +++ b/src/main/java/pulse/input/ExperimentalData.java @@ -419,7 +419,7 @@ private void doSetRange() { } /** - * Retrieves the + * Retrieves the time limit. * * @see pulse.problem.schemes.DifferenceScheme * @return a double, equal to the last element of the {@code time List}. @@ -427,6 +427,6 @@ private void doSetRange() { @Override public double timeLimit() { return timeAt(indexRange.getUpperBound()); - } + } } diff --git a/src/main/java/pulse/io/export/ExportManager.java b/src/main/java/pulse/io/export/ExportManager.java index ec8c81a..2064c50 100644 --- a/src/main/java/pulse/io/export/ExportManager.java +++ b/src/main/java/pulse/io/export/ExportManager.java @@ -21,6 +21,9 @@ * */ public class ExportManager { + + //current working dir + private static File cwd = null; private ExportManager() { // intentionally blank @@ -85,7 +88,7 @@ public static Exporter findExporter(Class target) public static void askToExport(T target, JFrame parentWindow, String fileTypeLabel) { var exporter = findExporter(target); if (exporter != null) { - exporter.askToExport(target, parentWindow, fileTypeLabel); + cwd = exporter.askToExport(target, parentWindow, fileTypeLabel, cwd); } else { throw new IllegalArgumentException("No exporter for " + target.getClass().getSimpleName()); } diff --git a/src/main/java/pulse/io/export/Exporter.java b/src/main/java/pulse/io/export/Exporter.java index 71cb1ba..d2d35c0 100644 --- a/src/main/java/pulse/io/export/Exporter.java +++ b/src/main/java/pulse/io/export/Exporter.java @@ -89,12 +89,11 @@ public default void export(T target, File directory, Extension extension) { * @param target the exported target * @param parentWindow the parent frame. * @param fileTypeLabel the label describing the specific type of files that - * will be saved. + * @param directory the default directory of the file will be saved. + * @return the directory where files were exported */ - public default void askToExport(T target, JFrame parentWindow, String fileTypeLabel) { - var fileChooser = new JFileChooser(); - var workingDirectory = new File(System.getProperty("user.home")); - fileChooser.setCurrentDirectory(workingDirectory); + public default File askToExport(T target, JFrame parentWindow, String fileTypeLabel, File directory) { + var fileChooser = new JFileChooser(directory); fileChooser.setMultiSelectionEnabled(true); FileNameExtensionFilter choosable = null; @@ -113,29 +112,35 @@ public default void askToExport(T target, JFrame parentWindow, String fileTypeLa var file = fileChooser.getSelectedFile(); var path = file.getPath(); - if (!(fileChooser.getFileFilter() instanceof FileNameExtensionFilter)) { - return; - } + directory = file.isDirectory() ? file : file.getParentFile(); - var currentFilter = (FileNameExtensionFilter) fileChooser.getFileFilter(); - var ext = currentFilter.getExtensions()[0]; + if ((fileChooser.getFileFilter() instanceof FileNameExtensionFilter)) { + + var currentFilter = (FileNameExtensionFilter) fileChooser.getFileFilter(); + var ext = currentFilter.getExtensions()[0]; + + if (!path.contains(".")) { + file = new File(path + "." + ext); + } else { + file = new File(path.substring(0, path.indexOf(".") + 1) + ext); + } + + try { + var fos = new FileOutputStream(file); + printToStream(target, fos, Extension.valueOf(ext.toUpperCase())); + fos.close(); + } catch (IOException e) { + System.err.println("An exception has been encountered while writing the contents of " + + target.getClass().getSimpleName() + " to " + file); + e.printStackTrace(); + } - if (!path.contains(".")) { - file = new File(path + "." + ext); - } - else - file = new File(path.substring(0, path.indexOf(".") + 1) + ext); - - try { - var fos = new FileOutputStream(file); - printToStream(target, fos, Extension.valueOf(ext.toUpperCase())); - fos.close(); - } catch (IOException e) { - System.err.println("An exception has been encountered while writing the contents of " - + target.getClass().getSimpleName() + " to " + file); - e.printStackTrace(); } + } + + return directory; + } /** diff --git a/src/main/java/pulse/io/readers/AbstractReader.java b/src/main/java/pulse/io/readers/AbstractReader.java index a557fcb..d98036e 100644 --- a/src/main/java/pulse/io/readers/AbstractReader.java +++ b/src/main/java/pulse/io/readers/AbstractReader.java @@ -13,6 +13,7 @@ * lists, arrays and containers may (and usually will) change as a result of * using the reader. *

+ * @param */ public interface AbstractReader extends AbstractHandler { diff --git a/src/main/java/pulse/io/readers/NetzschCSVReader.java b/src/main/java/pulse/io/readers/NetzschCSVReader.java index d3320e3..a50d4e7 100644 --- a/src/main/java/pulse/io/readers/NetzschCSVReader.java +++ b/src/main/java/pulse/io/readers/NetzschCSVReader.java @@ -7,10 +7,16 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; import pulse.AbstractData; import pulse.input.ExperimentalData; @@ -44,10 +50,16 @@ public class NetzschCSVReader implements CurveReader { /** * Note comma is included as a delimiter character here. */ - public final static String delims = "[#();,/°Cx%^]+"; - + private final static String ENGLISH_DELIMS = "[#(),/°Cx%^]+"; + private final static String GERMAN_DELIMS = "[#();/°Cx%^]+"; + + private static String delims = ENGLISH_DELIMS; + + //default number format (British format) + private static Locale locale = Locale.ENGLISH; + private NetzschCSVReader() { - // intentionally blank + //intentionally blank } /** @@ -87,19 +99,25 @@ public List read(File file) throws IOException { Objects.requireNonNull(file, Messages.getString("DATReader.1")); ExperimentalData curve = new ExperimentalData(); + + //gets the number format for this locale try (BufferedReader reader = new BufferedReader(new FileReader(file))) { int shotId = determineShotID(reader, file); + + var format = DecimalFormat.getInstance(locale); + format.setGroupingUsed(false); var tempTokens = findLineByLabel(reader, THICKNESS, delims).split(delims); - final double thickness = Double.parseDouble(tempTokens[tempTokens.length - 1]) * TO_METRES; + + final double thickness = format.parse(tempTokens[tempTokens.length - 1]).doubleValue() * TO_METRES; tempTokens = findLineByLabel(reader, DIAMETER, delims).split(delims); - final double diameter = Double.parseDouble(tempTokens[tempTokens.length - 1]) * TO_METRES; + final double diameter = format.parse(tempTokens[tempTokens.length - 1]).doubleValue() * TO_METRES; tempTokens = findLineByLabel(reader, SAMPLE_TEMPERATURE, delims).split(delims); - final double sampleTemperature = Double.parseDouble(tempTokens[tempTokens.length - 1]) + TO_KELVIN; + final double sampleTemperature = format.parse(tempTokens[tempTokens.length - 1]).doubleValue() + TO_KELVIN; /* * Finds the detector keyword. @@ -122,32 +140,52 @@ public List read(File file) throws IOException { curve.setMetadata(met); curve.setRange(new Range(curve.getTimeSequence())); + return new ArrayList<>(Arrays.asList(curve)); + } catch (ParseException ex) { + Logger.getLogger(NetzschCSVReader.class.getName()).log(Level.SEVERE, null, ex); } - return new ArrayList<>(Arrays.asList(curve)); + return null; } - protected static void populate(AbstractData data, BufferedReader reader) throws IOException { + protected static void populate(AbstractData data, BufferedReader reader) throws IOException, ParseException { double time; double power; String[] tokens; + var format = DecimalFormat.getInstance(locale); + format.setGroupingUsed(false); for (String line = reader.readLine(); line != null && !line.trim().isEmpty(); line = reader.readLine()) { tokens = line.split(delims); - time = Double.parseDouble(tokens[0]) * NetzschCSVReader.TO_SECONDS; - power = Double.parseDouble(tokens[1]); + time = format.parse(tokens[0]).doubleValue() * NetzschCSVReader.TO_SECONDS; + power = format.parse(tokens[1]).doubleValue(); data.addPoint(time, power); } } protected static int determineShotID(BufferedReader reader, File file) throws IOException { - String[] shotID = reader.readLine().split(delims); + String shotIDLine = reader.readLine(); + String[] shotID = shotIDLine.split(delims); int shotId = -1; + + if(shotID.length < 3) { + + if(locale == Locale.ENGLISH) { + delims = GERMAN_DELIMS; + locale = Locale.GERMAN; + } + else { + delims = ENGLISH_DELIMS; + locale = Locale.ENGLISH; + } + + shotID = shotIDLine.split(delims); + } //check if first entry makes sense if (!shotID[shotID.length - 2].equalsIgnoreCase(SHOT_DATA)) { @@ -160,19 +198,7 @@ protected static int determineShotID(BufferedReader reader, File file) throws IO return shotId; } - - /* - private double parseDoubleWithComma(String s) { - var format = NumberFormat.getInstance(Locale.GERMANY); - try { - return format.parse(s).doubleValue(); - } catch (ParseException e) { - System.out.println("Couldn't parse double from: " + s); - e.printStackTrace(); - } - return Double.NaN; - } - */ + protected static String findLineByLabel(BufferedReader reader, String label, String delims) throws IOException { String line = ""; @@ -195,7 +221,6 @@ protected static String findLineByLabel(BufferedReader reader, String label, Str return line; } - /** * As this class uses the singleton pattern, only one instance is created * using an empty no-argument constructor. @@ -205,5 +230,14 @@ protected static String findLineByLabel(BufferedReader reader, String label, Str public static CurveReader getInstance() { return instance; } - + + /** + * Get the standard delimiter chars. + * @return delims + */ + + public static String getDelims() { + return delims; + } + } diff --git a/src/main/java/pulse/io/readers/NetzschPulseCSVReader.java b/src/main/java/pulse/io/readers/NetzschPulseCSVReader.java index 2b67fe4..4ba3303 100644 --- a/src/main/java/pulse/io/readers/NetzschPulseCSVReader.java +++ b/src/main/java/pulse/io/readers/NetzschPulseCSVReader.java @@ -4,7 +4,10 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; +import java.text.ParseException; import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; import pulse.problem.laser.NumericPulseData; import pulse.ui.Messages; @@ -37,10 +40,12 @@ public String getSupportedExtension() { /** * This performs a basic check, finding the shot ID, which is then passed to - * a new {@code NumericPulseData} object. The latter is populated using the - * time-power sequence stored in this file. If the {@value PULSE} keyword is + * a new {@code NumericPulseData} object.The latter is populated using the + * time-power sequence stored in this file.If the {@value PULSE} keyword is * not found, the method will display an error. * + * @param file + * @throws java.io.IOException * @see pulse.io.readers.NetzschCSVReader.read() * @return a new {@code NumericPulseData} object encapsulating the contents * of {@code file} @@ -49,14 +54,14 @@ public String getSupportedExtension() { public NumericPulseData read(File file) throws IOException { Objects.requireNonNull(file, Messages.getString("DATReader.1")); - NumericPulseData data; + NumericPulseData data = null; try (BufferedReader reader = new BufferedReader(new FileReader(file))) { int shotId = NetzschCSVReader.determineShotID(reader, file); data = new NumericPulseData(shotId); - var pulseLabel = NetzschCSVReader.findLineByLabel(reader, PULSE, NetzschCSVReader.delims); + var pulseLabel = NetzschCSVReader.findLineByLabel(reader, PULSE, NetzschCSVReader.getDelims()); if (pulseLabel == null) { System.err.println("Skipping " + file.getName()); @@ -66,24 +71,14 @@ public NumericPulseData read(File file) throws IOException { reader.readLine(); NetzschCSVReader.populate(data, reader); + } catch (ParseException ex) { + Logger.getLogger(NetzschPulseCSVReader.class.getName()).log(Level.SEVERE, null, ex); } return data; } - /* - private double parseDoubleWithComma(String s) { - var format = NumberFormat.getInstance(Locale.GERMANY); - try { - return format.parse(s).doubleValue(); - } catch (ParseException e) { - System.out.println("Couldn't parse double from: " + s); - e.printStackTrace(); - } - return Double.NaN; - } - */ /** * As this class uses the singleton pattern, only one instance is created * using an empty no-argument constructor. diff --git a/src/main/java/pulse/io/readers/ReaderManager.java b/src/main/java/pulse/io/readers/ReaderManager.java index 83c72ee..97bc4a2 100644 --- a/src/main/java/pulse/io/readers/ReaderManager.java +++ b/src/main/java/pulse/io/readers/ReaderManager.java @@ -8,6 +8,12 @@ import java.util.Objects; import java.util.Scanner; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; @@ -207,13 +213,32 @@ public static Set readDirectory(List> readers, File dir throw new IllegalArgumentException("Not a directory: " + directory); } - var list = new HashSet(); - + var es = Executors.newSingleThreadExecutor(); + + var callableList = new ArrayList>(); + for (File f : directory.listFiles()) { - list.add(read(readers, f)); + Callable callable = () -> read(readers, f); + callableList.add(callable); + } + + Set result = new HashSet<>(); + + try { + List> futures = es.invokeAll(callableList); + + for(Future f : futures) + result.add(f.get()); + + } catch (InterruptedException ex) { + Logger.getLogger(ReaderManager.class.getName()).log(Level.SEVERE, + "Reading interrupted when loading files from " + directory.toString(), ex); + } catch (ExecutionException ex) { + Logger.getLogger(ReaderManager.class.getName()).log(Level.SEVERE, + "Error executing read operation using concurrency", ex); } - return list; + return result; } /** diff --git a/src/main/java/pulse/problem/statements/Problem.java b/src/main/java/pulse/problem/statements/Problem.java index acde58f..4b47ebd 100644 --- a/src/main/java/pulse/problem/statements/Problem.java +++ b/src/main/java/pulse/problem/statements/Problem.java @@ -16,6 +16,7 @@ import pulse.math.Segment; import pulse.math.transforms.InvLenSqTransform; import pulse.math.transforms.StandardTransformations; +import pulse.math.transforms.StickTransform; import pulse.problem.laser.DiscretePulse; import pulse.problem.schemes.DifferenceScheme; import pulse.problem.schemes.Grid; @@ -228,6 +229,13 @@ public void optimisationVector(ParameterVector output, List flags) { var key = output.getIndex(i); switch (key) { + case THICKNESS: + final double l = (double) properties.getSampleThickness().getValue(); + var bounds = Segment.boundsFrom(THICKNESS); + output.setParameterBounds(i, bounds); + output.setTransform(i, new StickTransform(bounds)); + output.set(i, l); + break; case DIFFUSIVITY: final double a = (double) properties.getDiffusivity().getValue(); output.setTransform(i, new InvLenSqTransform(properties)); @@ -284,6 +292,9 @@ public void assign(ParameterVector params) throws SolverException { var key = params.getIndex(i); switch (key) { + case THICKNESS: + properties.setSampleThickness(derive(THICKNESS, params.inverseTransform(i) )); + break; case DIFFUSIVITY: properties.setDiffusivity(derive(DIFFUSIVITY, params.inverseTransform(i))); break; diff --git a/src/main/java/pulse/properties/NumericPropertyFormatter.java b/src/main/java/pulse/properties/NumericPropertyFormatter.java index 1f98dc4..f3c83cf 100644 --- a/src/main/java/pulse/properties/NumericPropertyFormatter.java +++ b/src/main/java/pulse/properties/NumericPropertyFormatter.java @@ -74,7 +74,9 @@ public NumberFormat numberFormat(NumericProperty p) { : (double) value; double absAdjustedValue = Math.abs(adjustedValue); - if ((absAdjustedValue > UPPER_LIMIT) || (absAdjustedValue < LOWER_LIMIT && absAdjustedValue > ZERO)) { + if (addHtmlTags && + ( (absAdjustedValue > UPPER_LIMIT) + || (absAdjustedValue < LOWER_LIMIT && absAdjustedValue > ZERO)) ) { //format with scientific notations f = new ScientificFormat(p.getDimensionFactor(), p.getDimensionDelta()); } else { diff --git a/src/main/java/pulse/properties/NumericPropertyKeyword.java b/src/main/java/pulse/properties/NumericPropertyKeyword.java index 3a45116..65cdf46 100644 --- a/src/main/java/pulse/properties/NumericPropertyKeyword.java +++ b/src/main/java/pulse/properties/NumericPropertyKeyword.java @@ -210,23 +210,20 @@ public enum NumericPropertyKeyword { */ OPTICAL_THICKNESS, /** - * Time shift (pulse sync) + * Time shift (pulse sync). */ TIME_SHIFT, /** - * Statistical significance. + * Statistical significance for calculating the critical value. */ SIGNIFICANCE, - /** - * Statistical probability. - */ - PROBABILITY, + /** * Optimiser statistic (usually, RSS). */ OPTIMISER_STATISTIC, /** - * Model selection criterion (AIC, BIC, etc.) + * Model selection criterion (AIC, BIC, etc.). */ MODEL_CRITERION, /** diff --git a/src/main/java/pulse/search/direction/ActiveFlags.java b/src/main/java/pulse/search/direction/ActiveFlags.java index 5edc827..e13af6e 100644 --- a/src/main/java/pulse/search/direction/ActiveFlags.java +++ b/src/main/java/pulse/search/direction/ActiveFlags.java @@ -74,8 +74,8 @@ public static List activeParameters(SearchTask t) { //problem dependent var allActiveParams = selectActiveAndListed(flags, c.getProblem()); //problem independent (lower/upper bound) - var listed = selectActiveAndListed(flags, t.getExperimentalCurve() ); - allActiveParams.addAll( selectActiveAndListed(flags, t.getExperimentalCurve() ) ); + var listed = selectActiveAndListed(flags, t.getExperimentalCurve().getRange() ); + allActiveParams.addAll(listed); return allActiveParams; } diff --git a/src/main/java/pulse/search/statistics/AndersonDarlingTest.java b/src/main/java/pulse/search/statistics/AndersonDarlingTest.java index 60b970a..99ac004 100644 --- a/src/main/java/pulse/search/statistics/AndersonDarlingTest.java +++ b/src/main/java/pulse/search/statistics/AndersonDarlingTest.java @@ -1,7 +1,6 @@ package pulse.search.statistics; import static pulse.properties.NumericProperties.derive; -import static pulse.properties.NumericPropertyKeyword.PROBABILITY; import static pulse.properties.NumericPropertyKeyword.TEST_STATISTIC; import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation; @@ -32,9 +31,9 @@ public boolean test(SearchTask task) { var testResult = GofStat.andersonDarling(residuals, nd); this.setStatistic(derive(TEST_STATISTIC, testResult[0])); - setProbability(derive(PROBABILITY, testResult[1])); - - return significanceTest(); + + //compare the p-value and the significance + return testResult[1] > significance; } @Override diff --git a/src/main/java/pulse/search/statistics/KSTest.java b/src/main/java/pulse/search/statistics/KSTest.java index d350d7e..ceb4ceb 100644 --- a/src/main/java/pulse/search/statistics/KSTest.java +++ b/src/main/java/pulse/search/statistics/KSTest.java @@ -1,7 +1,6 @@ package pulse.search.statistics; import static pulse.properties.NumericProperties.derive; -import static pulse.properties.NumericPropertyKeyword.PROBABILITY; import static pulse.properties.NumericPropertyKeyword.TEST_STATISTIC; import org.apache.commons.math3.distribution.NormalDistribution; @@ -23,8 +22,10 @@ public class KSTest extends NormalityTest { @Override public boolean test(SearchTask task) { evaluate(task); - setProbability(derive(PROBABILITY, TestUtils.kolmogorovSmirnovTest(nd, residuals))); - return significanceTest(); + + this.setStatistic(derive(TEST_STATISTIC, + TestUtils.kolmogorovSmirnovStatistic(nd, residuals))); + return !TestUtils.kolmogorovSmirnovTest(nd, residuals, this.significance); } @Override diff --git a/src/main/java/pulse/search/statistics/NormalityTest.java b/src/main/java/pulse/search/statistics/NormalityTest.java index f7bb3ed..a8de54c 100644 --- a/src/main/java/pulse/search/statistics/NormalityTest.java +++ b/src/main/java/pulse/search/statistics/NormalityTest.java @@ -3,7 +3,6 @@ import static pulse.properties.NumericProperties.def; import static pulse.properties.NumericProperties.derive; import static pulse.properties.NumericProperty.requireType; -import static pulse.properties.NumericPropertyKeyword.PROBABILITY; import static pulse.properties.NumericPropertyKeyword.SIGNIFICANCE; import static pulse.properties.NumericPropertyKeyword.TEST_STATISTIC; @@ -17,28 +16,25 @@ * * For the test to pass, the model residuals need be distributed according to a * (0, σ) normal distribution, where σ is the variance of the model - * residuals. As this is the pre-requisite for optimizers based on the ordinary + * residuals. As this is the pre-requisite for optimisers based on the ordinary * least-square statistic, the normality test can also be used to estimate if a * fit 'failed' or 'succeeded' in describing the data. + * + * The test consists in testing the relation statistic < critValue, + * where the critical value is determined based on a given level of significance. * */ public abstract class NormalityTest extends ResidualStatistic { private double statistic; - private double probability; - private static double significance = (double) def(SIGNIFICANCE).getValue(); + protected static double significance = (double) def(SIGNIFICANCE).getValue(); private static String selectedTestDescriptor; protected NormalityTest() { - probability = (double) def(PROBABILITY).getValue(); statistic = (double) def(TEST_STATISTIC).getValue(); } - public boolean significanceTest() { - return probability > significance; - } - public static NumericProperty getStatisticalSignifiance() { return derive(SIGNIFICANCE, significance); } @@ -48,10 +44,6 @@ public static void setStatisticalSignificance(NumericProperty alpha) { NormalityTest.significance = (double) alpha.getValue(); } - public NumericProperty getProbability() { - return derive(PROBABILITY, probability); - } - public abstract boolean test(SearchTask task); @Override @@ -65,11 +57,6 @@ public void setStatistic(NumericProperty statistic) { this.statistic = (double) statistic.getValue(); } - public void setProbability(NumericProperty probability) { - requireType(probability, PROBABILITY); - this.probability = (double) probability.getValue(); - } - @Override public void set(NumericPropertyKeyword type, NumericProperty property) { if (type == TEST_STATISTIC) { diff --git a/src/main/java/pulse/tasks/Calculation.java b/src/main/java/pulse/tasks/Calculation.java index 797b9f8..60cdd4c 100644 --- a/src/main/java/pulse/tasks/Calculation.java +++ b/src/main/java/pulse/tasks/Calculation.java @@ -186,9 +186,10 @@ public boolean setStatus(Status status) { switch(this.status) { case DONE: + case IN_PROGRESS: + case FAILED: case EXECUTION_ERROR: case INCOMPLETE: - case IN_PROGRESS: //if the TaskManager attempts to run this calculation if(status == Status.QUEUED) return false; diff --git a/src/main/java/pulse/ui/Launcher.java b/src/main/java/pulse/ui/Launcher.java index 65e31e4..1ee2635 100644 --- a/src/main/java/pulse/ui/Launcher.java +++ b/src/main/java/pulse/ui/Launcher.java @@ -95,17 +95,7 @@ private void arrangeErrorOutput() { try { var dir = new File(decodedPath).getParent(); errorLog = new File(dir + File.separator + "ErrorLog_" + now() + ".log"); - setErr(new PrintStream(errorLog) { - - @Override - public void println(String str) { - super.println(str); - JOptionPane.showMessageDialog(null, "An exception has occurred. " - + "Please check the stored log!", "Exception", JOptionPane.ERROR_MESSAGE); - } - - } - ); + setErr(new PrintStream(errorLog)); } catch (FileNotFoundException e) { System.err.println("Unable to set up error stream"); e.printStackTrace(); diff --git a/src/main/java/pulse/ui/components/Chart.java b/src/main/java/pulse/ui/components/Chart.java index a485806..2158758 100644 --- a/src/main/java/pulse/ui/components/Chart.java +++ b/src/main/java/pulse/ui/components/Chart.java @@ -94,7 +94,7 @@ public void mouseDragged(MouseEvent e) { //process dragged events Range range = instance.getSelectedTask() .getExperimentalCurve().getRange(); - double value = xCoord(e); + double value = xCoord(e) / factor; //convert to seconds back from ms -- if needed if (lowerMarker.getState() != MovableValueMarker.State.IDLE) { if (range.boundLimits(false).contains(value)) { @@ -124,8 +124,8 @@ public void mouseDragged(MouseEvent e) { if (instance.getSelectedTask() == eventTask) { //update marker values var segment = eventTask.getExperimentalCurve().getRange().getSegment(); - lowerMarker.setValue(segment.getMinimum()); - upperMarker.setValue(segment.getMaximum()); + lowerMarker.setValue(segment.getMinimum() * factor); //convert to ms -- if needed + upperMarker.setValue(segment.getMaximum() * factor); //convert to ms -- if needed } }); } //tasks that have been finihed @@ -241,11 +241,11 @@ public void plot(SearchTask task, boolean extendedCurve) { lowerMarker = new MovableValueMarker(segment.getMinimum() * factor); upperMarker = new MovableValueMarker(segment.getMaximum() * factor); - final double margin = segment.getMaximum() / 20.0; + final double margin = (lowerMarker.getValue() + upperMarker.getValue())/20.0; //add listener to handle range adjustment - var lowerMarkerListener = new MouseOnMarkerListener(this, lowerMarker, margin); - var upperMarkerListener = new MouseOnMarkerListener(this, upperMarker, margin); + var lowerMarkerListener = new MouseOnMarkerListener(this, lowerMarker, upperMarker, margin); + var upperMarkerListener = new MouseOnMarkerListener(this, upperMarker, upperMarker, margin); chartPanel.addChartMouseListener(lowerMarkerListener); chartPanel.addChartMouseListener(upperMarkerListener); diff --git a/src/main/java/pulse/ui/components/listeners/MouseOnMarkerListener.java b/src/main/java/pulse/ui/components/listeners/MouseOnMarkerListener.java index 4a4d1ef..834dc1c 100644 --- a/src/main/java/pulse/ui/components/listeners/MouseOnMarkerListener.java +++ b/src/main/java/pulse/ui/components/listeners/MouseOnMarkerListener.java @@ -27,16 +27,19 @@ */ public class MouseOnMarkerListener implements ChartMouseListener { - private final MovableValueMarker marker; + private final MovableValueMarker lower; + private final MovableValueMarker upper; + private final Chart chart; private final double margin; private final static Cursor CROSSHAIR = new Cursor(Cursor.CROSSHAIR_CURSOR); private final static Cursor RESIZE = new Cursor(Cursor.E_RESIZE_CURSOR); - public MouseOnMarkerListener(Chart chart, MovableValueMarker marker, double margin) { + public MouseOnMarkerListener(Chart chart, MovableValueMarker lower, MovableValueMarker upper, double margin) { this.chart = chart; - this.marker = marker; + this.lower = lower; + this.upper = upper; this.margin = margin; } @@ -48,20 +51,29 @@ public void chartMouseClicked(ChartMouseEvent arg0) { @Override public void chartMouseMoved(ChartMouseEvent arg0) { double xCoord = chart.xCoord(arg0.getTrigger()); - highlightMarker(xCoord, marker); + highlightMarker(xCoord); } - private void highlightMarker(double xCoord, MovableValueMarker marker) { + private void highlightMarker(double xCoord) { - if (xCoord > (marker.getValue() - margin) - & xCoord < (marker.getValue() + margin)) { + if (xCoord > (lower.getValue() - margin) + & xCoord < (lower.getValue() + margin)) { - marker.setState(MovableValueMarker.State.SELECTED); + lower.setState(MovableValueMarker.State.SELECTED); chart.getChartPanel().setCursor(RESIZE); - } else { + } + else if (xCoord > (upper.getValue() - margin) + & xCoord < (upper.getValue() + margin)) { + + upper.setState(MovableValueMarker.State.SELECTED); + chart.getChartPanel().setCursor(RESIZE); + + } + else { - marker.setState(MovableValueMarker.State.IDLE); + lower.setState(MovableValueMarker.State.IDLE); + upper.setState(MovableValueMarker.State.IDLE); chart.getChartPanel().setCursor(CROSSHAIR); } diff --git a/src/main/java/pulse/ui/frames/MainGraphFrame.java b/src/main/java/pulse/ui/frames/MainGraphFrame.java index 3d81254..fff33ec 100644 --- a/src/main/java/pulse/ui/frames/MainGraphFrame.java +++ b/src/main/java/pulse/ui/frames/MainGraphFrame.java @@ -8,6 +8,7 @@ import javax.swing.JInternalFrame; import pulse.tasks.TaskManager; +import pulse.tasks.logs.Status; import pulse.ui.components.Chart; import pulse.ui.components.panels.ChartToolbar; import pulse.ui.components.panels.OpacitySlider; @@ -44,7 +45,8 @@ private void initComponents() { public void plot() { var task = TaskManager.getManagerInstance().getSelectedTask(); - if (task != null) { + //do not plot tasks that are not finished + if (task != null && task.getCurrentCalculation().getStatus() != Status.IN_PROGRESS) { Executors.newSingleThreadExecutor().submit(() -> chart.plot(task, false)); } } diff --git a/src/main/java/pulse/ui/frames/SearchOptionsFrame.java b/src/main/java/pulse/ui/frames/SearchOptionsFrame.java index d8b0b6c..2d7edda 100644 --- a/src/main/java/pulse/ui/frames/SearchOptionsFrame.java +++ b/src/main/java/pulse/ui/frames/SearchOptionsFrame.java @@ -50,7 +50,7 @@ public class SearchOptionsFrame extends JInternalFrame { private final static Font FONT = new Font(getString("PropertyHolderTable.FontName"), ITALIC, 16); private final static List pathSolvers = instancesOf(PathOptimiser.class); - private final NumericPropertyKeyword[] mandatorySelection = new NumericPropertyKeyword[]{DIFFUSIVITY, MAXTEMP}; + private final NumericPropertyKeyword[] mandatorySelection = new NumericPropertyKeyword[]{MAXTEMP}; /** * Create the frame. diff --git a/src/main/java/pulse/ui/frames/dialogs/ExportDialog.java b/src/main/java/pulse/ui/frames/dialogs/ExportDialog.java index f8a9300..ed0f7ee 100644 --- a/src/main/java/pulse/ui/frames/dialogs/ExportDialog.java +++ b/src/main/java/pulse/ui/frames/dialogs/ExportDialog.java @@ -14,6 +14,7 @@ import java.awt.Dimension; import java.io.File; +import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @@ -81,12 +82,12 @@ public ExportDialog() { } private File directoryQuery() { - var returnVal = fileChooser.showSaveDialog(this); + var returnVal = fileChooser.showOpenDialog(this); File f = null; if (returnVal == APPROVE_OPTION) { - f = fileChooser.getCurrentDirectory(); + dir = f = fileChooser.getSelectedFile(); } return f; @@ -171,8 +172,9 @@ private void initComponents() { fileChooser = new JFileChooser(); fileChooser.setMultiSelectionEnabled(false); fileChooser.setFileSelectionMode(DIRECTORIES_ONLY); - // Checkboxex - dir = fileChooser.getCurrentDirectory(); + + //get cwd + dir = new File("").getAbsoluteFile(); var directoryField = new JTextField(dir.getPath() + separator + projectName + separator); directoryField.setEditable(false); @@ -247,11 +249,8 @@ public void removeUpdate(DocumentEvent e) { var browseBtn = new JButton("Browse..."); - browseBtn.addActionListener(e -> { - if (directoryQuery() != null) { - directoryField.setText(dir.getPath() + separator + projectName + separator); - } - }); + browseBtn.addActionListener(e -> directoryField.setText(directoryQuery() + .getPath() + separator + projectName + separator) ); var exportBtn = new JButton("Export"); diff --git a/src/main/resources/NumericProperty.xml b/src/main/resources/NumericProperty.xml index 89dca9d..9c78b74 100644 --- a/src/main/resources/NumericProperty.xml +++ b/src/main/resources/NumericProperty.xml @@ -1,5 +1,10 @@ + + - - - + - - + minimum="1.0E-6" value="0.001" primitive-type="double" discreet="true" + default-search-variable="false">