+ * This can change the {@code tauFactor} and {@code tau} variables in the
+ * {@code Grid} object if {@code discretePulseWidth/(M - 1) < grid.tau},
+ * where M is the required number of pulse calculations.
+ *
+ *
+ * @see PulseTemporalShape.getRequiredDiscretisation()
*/
+ public double pulseWidthGrid() {
+ //minimum number of points for pulse calculation
+ int reqPoints = pulse.getPulseShape().getRequiredDiscretisation();
+ //physical pulse width in time units
+ double experimentalWidth = (double) pulse.getPulseWidth().getValue();
+
+ //minimum resolved pulse width in time units for that specific problem
+ double resolvedWidth = resolvedPulseWidthSeconds();
+
+ double pWidth = Math.max(experimentalWidth, resolvedWidth);
+
+ final double EPS = 1E-10;
+ double newTau = pWidth / characteristicTime / reqPoints;
+
+ double result = 0;
+
+ if (newTau < grid.getTimeStep() - EPS) {
+ double newTauFactor = (double) grid.getTimeFactor().getValue() / 2.0;
+ grid.setTimeFactor(derive(TAU_FACTOR, newTauFactor));
+ result = pulseWidthGrid();
+ } else {
+ result = grid.gridTime(pWidth, characteristicTime);
+ }
+
+ return result;
+ }
+
+ /**
+ * Calculates the total pulse energy using a numerical integrator.The
+ * normalisation factor is then equal to the inverse total energy.
+ *
+ * @return the total pulse energy, assuming sample area fully covered by the
+ * beam
+ */
public final double totalEnergy() {
var pulseShape = pulse.getPulseShape();
@@ -144,27 +181,22 @@ public double integrand(double... vars) {
}
/**
- * Gets the discrete dimensionless pulse width, which is a multiplier of the current
- * grid timestep. The pulse width is converted to the dimensionless pulse width by
- * dividing the real value by
- * This can change the {@code tauFactor} and {@code tau} variables in the
- * {@code Grid} object if {@code discretePulseWidth/(M - 1) < grid.tau},
- * where M is the required number of pulse calculations.
- *
- *
- * @param pulse the discrete pulse representation
- * @see PulseTemporalShape.getRequiredDiscretisation()
- */
- public final void adjustTimeStep(DiscretePulse pulse) {
- double timeFactor = pulse.getConversionFactor();
-
- final int reqPoints = pulse.getPulse().getPulseShape().getRequiredDiscretisation();
-
- double pNominalWidth = (double) pulse.getPulse().getPulseWidth().getValue();
- double pResolvedWidth = pulse.resolvedPulseWidth();
- double pWidth = pNominalWidth < pResolvedWidth ? pResolvedWidth : pNominalWidth;
-
- double newTau = pWidth / timeFactor / (reqPoints > 1 ? reqPoints - 1 : 1);
- double newTauFactor = newTau / (hx * hx);
-
- final double EPS = 1E-10;
- if (newTauFactor < tauFactor - EPS) {
- setTimeFactor(derive(TAU_FACTOR, newTauFactor));
- }
-
- }
-
/**
* The listed properties include {@code GRID_DENSITY} and
* {@code TAU_FACTOR}.
@@ -223,7 +193,7 @@ public void setTimeFactor(NumericProperty timeFactor) {
* @return a double representing the time on the finite grid
*/
public final double gridTime(double time, double dimensionFactor) {
- return rint((time / dimensionFactor) / tau) * tau;
+ return ( (int) (time / dimensionFactor / tau) ) * tau;
}
/**
diff --git a/src/main/java/pulse/problem/schemes/Grid2D.java b/src/main/java/pulse/problem/schemes/Grid2D.java
index 7c34840..af2284b 100644
--- a/src/main/java/pulse/problem/schemes/Grid2D.java
+++ b/src/main/java/pulse/problem/schemes/Grid2D.java
@@ -46,7 +46,7 @@ public Grid2D copy() {
@Override
public void setTimeFactor(NumericProperty timeFactor) {
super.setTimeFactor(timeFactor);
- setTimeStep((double) timeFactor.getValue() * (pow(getXStep(), 2) + pow(hy, 2)));
+ setTimeStep((double) timeFactor.getValue() * (pow(getXStep(), 2) + pow(hy, 2)) );
}
/**
@@ -68,7 +68,6 @@ public void adjustStepSize(DiscretePulse pulse) {
adjustStepSize(pulse);
}
- adjustTimeStep(pulse);
}
@Override
diff --git a/src/main/java/pulse/problem/statements/AdiabaticSolution.java b/src/main/java/pulse/problem/statements/AdiabaticSolution.java
index a335fac..5fbb5a8 100644
--- a/src/main/java/pulse/problem/statements/AdiabaticSolution.java
+++ b/src/main/java/pulse/problem/statements/AdiabaticSolution.java
@@ -75,7 +75,7 @@ public static HeatingCurve classicSolution(Problem p, double timeLimit, int prec
private final static double solutionAt(ThermalProperties p, double time, int precision) {
final double EPS = 1E-8;
- final double Fo = time / p.timeFactor();
+ final double Fo = time / p.characteristicTime();
if (time < EPS) {
return 0;
diff --git a/src/main/java/pulse/problem/statements/ClassicalProblem2D.java b/src/main/java/pulse/problem/statements/ClassicalProblem2D.java
index 74b74e0..9960a8b 100644
--- a/src/main/java/pulse/problem/statements/ClassicalProblem2D.java
+++ b/src/main/java/pulse/problem/statements/ClassicalProblem2D.java
@@ -28,7 +28,7 @@
* pulse-to-diameter ratio.
*
*/
-public class ClassicalProblem2D extends Problem {
+public class ClassicalProblem2D extends ClassicalProblem {
public ClassicalProblem2D() {
super();
@@ -82,12 +82,14 @@ public void optimisationVector(ParameterVector output) {
switch (key) {
case FOV_OUTER:
value = (double) properties.getFOVOuter().getValue();
+ transform = new StickTransform(bounds);
break;
case FOV_INNER:
value = (double) properties.getFOVInner().getValue();
break;
case SPOT_DIAMETER:
value = (double) ((Pulse2D) getPulse()).getSpotDiameter().getValue();
+ transform = new StickTransform(bounds);
break;
case HEAT_LOSS_SIDE:
value = (double) properties.getSideLosses().getValue();
diff --git a/src/main/java/pulse/problem/statements/Problem.java b/src/main/java/pulse/problem/statements/Problem.java
index f228515..a9752e2 100644
--- a/src/main/java/pulse/problem/statements/Problem.java
+++ b/src/main/java/pulse/problem/statements/Problem.java
@@ -6,6 +6,7 @@
import static pulse.properties.NumericPropertyKeyword.TIME_SHIFT;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
@@ -245,7 +246,7 @@ public void optimisationVector(ParameterVector output) {
p.setTransform(new StickTransform(bounds));
break;
case TIME_SHIFT:
- double magnitude = 0.25 * properties.timeFactor();
+ double magnitude = 0.25 * properties.characteristicTime();
bounds = new Segment(-magnitude, magnitude);
value = (double) curve.getTimeShift().getValue();
break;
@@ -446,4 +447,4 @@ public final void setProperties(ThermalProperties properties) {
public abstract boolean isReady();
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/problem/statements/Pulse.java b/src/main/java/pulse/problem/statements/Pulse.java
index 1b0fbf3..eac31f9 100644
--- a/src/main/java/pulse/problem/statements/Pulse.java
+++ b/src/main/java/pulse/problem/statements/Pulse.java
@@ -7,7 +7,6 @@
import static pulse.properties.NumericPropertyKeyword.PULSE_WIDTH;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import pulse.input.ExperimentalData;
@@ -217,7 +216,8 @@ public PulseTemporalShape getPulseShape() {
public void setPulseShape(PulseTemporalShape pulseShape) {
this.pulseShape = pulseShape;
- pulseShape.setParent(this);
+ pulseShape.setParent(this);
+
}
}
diff --git a/src/main/java/pulse/problem/statements/model/ThermalProperties.java b/src/main/java/pulse/problem/statements/model/ThermalProperties.java
index 153faa1..295f6b8 100644
--- a/src/main/java/pulse/problem/statements/model/ThermalProperties.java
+++ b/src/main/java/pulse/problem/statements/model/ThermalProperties.java
@@ -325,7 +325,7 @@ public double maxRadiationBiot() {
*
* @return the time factor
*/
- public double timeFactor() {
+ public double characteristicTime() {
return l * l / a;
}
diff --git a/src/main/java/pulse/properties/NumericProperties.java b/src/main/java/pulse/properties/NumericProperties.java
index cd5279e..738885a 100644
--- a/src/main/java/pulse/properties/NumericProperties.java
+++ b/src/main/java/pulse/properties/NumericProperties.java
@@ -1,11 +1,8 @@
package pulse.properties;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
import java.util.List;
import pulse.io.export.XMLConverter;
-import pulse.ui.Messages;
/**
* Default operations with NumericProperties
@@ -59,9 +56,9 @@ public static String printRangeAndNumber(NumericProperty p, Number value) {
msg.append("Acceptable region for ");
msg.append("parameter : ");
msg.append(p.getValue().getClass().getSimpleName());
- msg.append(" [ " + p.getMinimum());
- msg.append(" : " + p.getMaximum() + " ]. ");
- msg.append("Value received: " + value);
+ msg.append(" [ ").append(p.getMinimum());
+ msg.append(" : ").append(p.getMaximum()).append(" ]. ");
+ msg.append("Value received: ").append(value);
return msg.toString();
}
diff --git a/src/main/java/pulse/properties/NumericPropertyKeyword.java b/src/main/java/pulse/properties/NumericPropertyKeyword.java
index a657171..36b1666 100644
--- a/src/main/java/pulse/properties/NumericPropertyKeyword.java
+++ b/src/main/java/pulse/properties/NumericPropertyKeyword.java
@@ -390,7 +390,13 @@ public enum NumericPropertyKeyword {
* Heat loss for the gas in the 2T-model.
*/
- HEAT_LOSS_GAS;
+ HEAT_LOSS_GAS,
+
+ /**
+ * Value of objective function.
+ */
+
+ OBJECTIVE_FUNCTION;
public static Optional findAny(String key) {
return Arrays.asList(values()).stream().filter(keys -> keys.toString().equalsIgnoreCase(key)).findAny();
diff --git a/src/main/java/pulse/search/GeneralTask.java b/src/main/java/pulse/search/GeneralTask.java
index 44c64ac..3bd42d0 100644
--- a/src/main/java/pulse/search/GeneralTask.java
+++ b/src/main/java/pulse/search/GeneralTask.java
@@ -64,6 +64,7 @@ public GeneralTask() {
@Override
public void run() {
setDefaultOptimiser();
+ best = null;
setIterativeState( optimiser.initState(this) );
var errorTolerance = (double) optimiser.getErrorTolerance().getValue();
diff --git a/src/main/java/pulse/search/direction/ComplexPath.java b/src/main/java/pulse/search/direction/ComplexPath.java
index e6fc8a3..bfe1ef8 100644
--- a/src/main/java/pulse/search/direction/ComplexPath.java
+++ b/src/main/java/pulse/search/direction/ComplexPath.java
@@ -4,7 +4,6 @@
import pulse.math.linear.SquareMatrix;
import pulse.search.GeneralTask;
-import pulse.tasks.SearchTask;
/**
*
diff --git a/src/main/java/pulse/search/direction/CompositePathOptimiser.java b/src/main/java/pulse/search/direction/CompositePathOptimiser.java
index 7976646..48766c5 100644
--- a/src/main/java/pulse/search/direction/CompositePathOptimiser.java
+++ b/src/main/java/pulse/search/direction/CompositePathOptimiser.java
@@ -61,6 +61,7 @@ public boolean iteration(GeneralTask task) throws SolverException {
} else {
double initialCost = task.getResponse().objectiveFunction(task);
+ p.setCost(initialCost);
var parameters = task.searchVector();
p.setParameters(parameters); // store current parameters
@@ -94,6 +95,7 @@ public boolean iteration(GeneralTask task) throws SolverException {
task.storeState();
p.resetFailedAttempts();
this.prepare(task); // update gradients, Hessians, etc. -> for the next step, [k + 1]
+ p.setCost(newCost);
p.incrementStep(); // increment the counter of successful steps
}
@@ -142,4 +144,4 @@ public GradientGuidedPath initState(GeneralTask t) {
return new ComplexPath(t);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/search/direction/IterativeState.java b/src/main/java/pulse/search/direction/IterativeState.java
index 05fbaca..9045d46 100644
--- a/src/main/java/pulse/search/direction/IterativeState.java
+++ b/src/main/java/pulse/search/direction/IterativeState.java
@@ -41,6 +41,7 @@ public void setCost(double cost) {
public void reset() {
iteration = 0;
+ setCost(Double.POSITIVE_INFINITY);
}
public NumericProperty getIteration() {
diff --git a/src/main/java/pulse/search/direction/LMOptimiser.java b/src/main/java/pulse/search/direction/LMOptimiser.java
index 4c3247a..86ee9e4 100644
--- a/src/main/java/pulse/search/direction/LMOptimiser.java
+++ b/src/main/java/pulse/search/direction/LMOptimiser.java
@@ -69,6 +69,7 @@ public boolean iteration(GeneralTask task) throws SolverException {
} else {
double initialCost = task.objectiveFunction();
+ p.setCost(initialCost);
var parameters = task.searchVector();
p.setParameters(parameters); // store current parameters
@@ -88,7 +89,7 @@ public boolean iteration(GeneralTask task) throws SolverException {
parameters, candidate)); // assign new parameters
double newCost = task.objectiveFunction(); // calculate the sum of squared residuals
-
+
/*
* Delayed gratification
*/
@@ -103,6 +104,7 @@ public boolean iteration(GeneralTask task) throws SolverException {
p.resetFailedAttempts();
p.setLambda(p.getLambda() / 3.0);
p.setComputeJacobian(false);
+ p.setCost(newCost);
p.incrementStep(); // increment the counter of successful steps
}
diff --git a/src/main/java/pulse/search/direction/pso/ParticleSwarmOptimiser.java b/src/main/java/pulse/search/direction/pso/ParticleSwarmOptimiser.java
index 6f39f8b..323dfab 100644
--- a/src/main/java/pulse/search/direction/pso/ParticleSwarmOptimiser.java
+++ b/src/main/java/pulse/search/direction/pso/ParticleSwarmOptimiser.java
@@ -46,7 +46,8 @@ public boolean iteration(GeneralTask task) throws SolverException {
swarmState.incrementStep();
task.assign(swarmState.getBestSoFar().getPosition());
- task.objectiveFunction();
+ double cost = task.objectiveFunction();
+ swarmState.setCost(cost);
return true;
}
diff --git a/src/main/java/pulse/search/statistics/AICStatistic.java b/src/main/java/pulse/search/statistics/AICStatistic.java
index 529b2e6..3279461 100644
--- a/src/main/java/pulse/search/statistics/AICStatistic.java
+++ b/src/main/java/pulse/search/statistics/AICStatistic.java
@@ -11,7 +11,7 @@ public AICStatistic(OptimiserStatistic os) {
super(os);
}
- public AICStatistic(AICStatistic another) {
+ public AICStatistic(ModelSelectionCriterion another) {
super(another);
}
diff --git a/src/main/java/pulse/search/statistics/BICStatistic.java b/src/main/java/pulse/search/statistics/BICStatistic.java
index 2c6edfe..72409f0 100644
--- a/src/main/java/pulse/search/statistics/BICStatistic.java
+++ b/src/main/java/pulse/search/statistics/BICStatistic.java
@@ -11,7 +11,7 @@
*/
public class BICStatistic extends ModelSelectionCriterion {
- public BICStatistic(BICStatistic another) {
+ public BICStatistic(ModelSelectionCriterion another) {
super(another);
}
diff --git a/src/main/java/pulse/search/statistics/FTest.java b/src/main/java/pulse/search/statistics/FTest.java
index 9a39bc4..4723f5f 100644
--- a/src/main/java/pulse/search/statistics/FTest.java
+++ b/src/main/java/pulse/search/statistics/FTest.java
@@ -4,130 +4,137 @@
import pulse.tasks.Calculation;
/**
- * A static class for testing two calculations based on the Fischer test (F-Test)
- * implemented in Apache Commons Math.
+ * A static class for testing two calculations based on the Fischer test
+ * (F-Test) implemented in Apache Commons Math.
*/
public class FTest {
-
+
/**
- * False-rejection probability for the F-test, equal to {@value FALSE_REJECTION_PROBABILITY}
+ * False-rejection probability for the F-test, equal to
+ * {@value FALSE_REJECTION_PROBABILITY}
*/
-
public final static double FALSE_REJECTION_PROBABILITY = 0.05;
-
+
private FTest() {
//intentionall blank
}
-
+
/**
* Tests two models to see which one is better according to the F-test
+ *
* @param a a calculation
* @param b another calculation
- * @return {@code null} if the result is inconclusive, otherwise the
- * best of two calculations.
+ * @return {@code null} if the result is inconclusive, otherwise the best of
+ * two calculations.
* @see FTest.evaluate()
*/
-
public static Calculation test(Calculation a, Calculation b) {
-
+
double[] data = evaluate(a, b);
-
- Calculation best = null;
-
- if(data != null) {
-
+
+ Calculation best = null;
+
+ if (data != null) {
+
//Under the null hypothesis the general model does not provide
//a significantly better fit than the nested model
-
Calculation nested = findNested(a, b);
-
+
//if the F-statistic is greater than the F-critical, reject the null hypothesis.
-
- if(nested == a)
+ if (nested == a) {
best = data[0] > data[1] ? b : a;
- else
+ } else {
best = data[0] > data[1] ? a : b;
-
+ }
+
}
-
+
return best;
-
+
}
-
+
/**
- * Evaluates the F-statistic for two calculations.
+ * Evaluates the F-statistic for two calculations.
+ *
* @param a a calculation
* @param b another calculation
- * @return {@code null} if the test is inconclusive, i.e., if models are not
- * nested, or if the model selection criteria are based on a statistic different
- * from least-squares, or if the calculations refer to different data ranges.
- * Otherwise returns an double array, consisting of two elements {@code [fStatistic, fCritical] }
+ * @return {@code null} if the test is inconclusive, i.e., if models are not
+ * nested, or if the model selection criteria are based on a statistic
+ * different from least-squares, or if the calculations refer to different
+ * data ranges. Otherwise returns an double array, consisting of two
+ * elements {@code [fStatistic, fCritical] }
*/
-
public static double[] evaluate(Calculation a, Calculation b) {
-
+
Calculation nested = findNested(a, b);
-
+
double[] result = null;
-
+
//if one of the models is nested into the other
- if(nested != null) {
+ if (nested != null) {
Calculation general = nested == a ? b : a;
-
+
ResidualStatistic nestedResiduals = nested.getModelSelectionCriterion().getOptimiserStatistic();
- ResidualStatistic generalResiduals = general.getModelSelectionCriterion().getOptimiserStatistic();
+ ResidualStatistic generalResiduals = general.getModelSelectionCriterion().getOptimiserStatistic();
final int nNested = nestedResiduals.getResiduals().size(); //sample size
final int nGeneral = generalResiduals.getResiduals().size(); //sample size
-
+
//if both models use a sum-of-square statistic for the model selection criteria
//and if both calculations refer to the same calculation range
- if(nestedResiduals.getClass() == generalResiduals.getClass()
- && nestedResiduals.getClass() == SumOfSquares.class
+ if (nestedResiduals.getClass() == generalResiduals.getClass()
+ && nestedResiduals.getClass() == SumOfSquares.class
&& nNested == nGeneral) {
-
- double rssNested = ( (Number) ((SumOfSquares)nestedResiduals).getStatistic().getValue() ).doubleValue();
- double rssGeneral = ( (Number) ((SumOfSquares)generalResiduals).getStatistic().getValue() ).doubleValue();
-
- int kGeneral = general.getModelSelectionCriterion().getNumVariables();
- int kNested = nested.getModelSelectionCriterion().getNumVariables();
-
- double fStatistic = (rssNested - rssGeneral)
- /(kGeneral - kNested)
- /(rssGeneral/(nGeneral - kGeneral));
-
- var fDistribution = new FDistribution(kGeneral - kNested, nGeneral - kGeneral);
-
- double fCritical = fDistribution.inverseCumulativeProbability(1.0 - FALSE_REJECTION_PROBABILITY);
-
- result = new double[]{fStatistic, fCritical};
-
+
+ double rssNested = ((Number) ((SumOfSquares) nestedResiduals).getStatistic().getValue()).doubleValue();
+ double rssGeneral = ((Number) ((SumOfSquares) generalResiduals).getStatistic().getValue()).doubleValue();
+
+ int kGeneral = general.getModelSelectionCriterion().getNumVariables();
+ int kNested = nested.getModelSelectionCriterion().getNumVariables();
+
+ if (kGeneral > kNested && nGeneral > kGeneral) {
+
+ double fStatistic = (rssNested - rssGeneral)
+ / (kGeneral - kNested)
+ / (rssGeneral / (nGeneral - kGeneral));
+
+ var fDistribution = new FDistribution(kGeneral - kNested, nGeneral - kGeneral);
+
+ double fCritical = fDistribution.inverseCumulativeProbability(1.0 - FALSE_REJECTION_PROBABILITY);
+
+ result = new double[]{fStatistic, fCritical};
+
+ }
+
}
-
+
}
-
+
return result;
-
+
}
-
+
/**
- * Tests two models to see which one is nested in the other. A model is
- * considered nested if it refers to the same class of problems but has
+ * Tests two models to see which one is nested in the other. A model is
+ * considered nested if it refers to the same class of problems but has
* fewer parameters.
+ *
* @param a a calculation
* @param b another calculation
* @return {@code null} if the models refer to different problem classes.
* Otherwise returns the model that is nested in the second model.
*/
-
public static Calculation findNested(Calculation a, Calculation b) {
- if(a.getProblem().getClass() != b.getProblem().getClass())
- return null;
-
- int aParams = a.getModelSelectionCriterion().getNumVariables();
- int bParams = b.getModelSelectionCriterion().getNumVariables();
-
- return aParams > bParams ? b : a;
+ var classA = a.getProblem().getClass();
+ var classB = b.getProblem().getClass();
+ if (!classA.isAssignableFrom(classB) && !classB.isAssignableFrom(classA)) {
+ return null;
+ }
+
+ int aParams = a.getModelSelectionCriterion().getNumVariables();
+ int bParams = b.getModelSelectionCriterion().getNumVariables();
+
+ return aParams > bParams ? b : a;
}
-
+
}
\ No newline at end of file
diff --git a/src/main/java/pulse/search/statistics/ModelSelectionCriterion.java b/src/main/java/pulse/search/statistics/ModelSelectionCriterion.java
index fbba1cc..6951845 100644
--- a/src/main/java/pulse/search/statistics/ModelSelectionCriterion.java
+++ b/src/main/java/pulse/search/statistics/ModelSelectionCriterion.java
@@ -37,6 +37,35 @@ public ModelSelectionCriterion(ModelSelectionCriterion another) {
this.criterion = another.criterion;
}
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 43 * hash + this.kq;
+ hash = 43 * hash + (int) (Double.doubleToLongBits(this.criterion) ^ (Double.doubleToLongBits(this.criterion) >>> 32));
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ModelSelectionCriterion other = (ModelSelectionCriterion) obj;
+ if (this.kq != other.kq) {
+ return false;
+ }
+ if (Double.doubleToLongBits(this.criterion) != Double.doubleToLongBits(other.criterion)) {
+ return false;
+ }
+ return true;
+ }
+
@Override
public void evaluate(GeneralTask t) {
kq = t.searchVector().dimension(); //number of parameters
diff --git a/src/main/java/pulse/search/statistics/ResidualStatistic.java b/src/main/java/pulse/search/statistics/ResidualStatistic.java
index a00ad58..5b9d3e5 100644
--- a/src/main/java/pulse/search/statistics/ResidualStatistic.java
+++ b/src/main/java/pulse/search/statistics/ResidualStatistic.java
@@ -6,6 +6,7 @@
import static pulse.properties.NumericPropertyKeyword.OPTIMISER_STATISTIC;
import java.util.List;
+import java.util.Objects;
import pulse.DiscreteInput;
import pulse.Response;
import pulse.input.IndexRange;
@@ -31,6 +32,39 @@ public abstract class ResidualStatistic extends Statistic {
private List rx;
private List ry;
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 53 * hash + (int) (Double.doubleToLongBits(this.statistic) ^ (Double.doubleToLongBits(this.statistic) >>> 32));
+ hash = 53 * hash + Objects.hashCode(this.rx);
+ hash = 53 * hash + Objects.hashCode(this.ry);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final ResidualStatistic other = (ResidualStatistic) obj;
+ if (Double.doubleToLongBits(this.statistic) != Double.doubleToLongBits(other.statistic)) {
+ return false;
+ }
+ if (!Objects.equals(this.rx, other.rx)) {
+ return false;
+ }
+ if (!Objects.equals(this.ry, other.ry)) {
+ return false;
+ }
+ return true;
+ }
+
public ResidualStatistic() {
super();
ry = new ArrayList<>();
@@ -40,8 +74,8 @@ public ResidualStatistic() {
public ResidualStatistic(ResidualStatistic another) {
this.statistic = another.statistic;
- ry = new ArrayList<>();
- rx = new ArrayList<>();
+ ry = new ArrayList<>(another.rx);
+ rx = new ArrayList<>(another.ry);
}
/**
@@ -144,4 +178,4 @@ public void set(NumericPropertyKeyword type, NumericProperty property) {
}
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/tasks/Calculation.java b/src/main/java/pulse/tasks/Calculation.java
index 4755a1d..2e38a79 100644
--- a/src/main/java/pulse/tasks/Calculation.java
+++ b/src/main/java/pulse/tasks/Calculation.java
@@ -9,6 +9,7 @@
import static pulse.util.Reflexive.instantiate;
import java.util.List;
+import java.util.Objects;
import java.util.stream.Collectors;
import pulse.Response;
@@ -27,12 +28,14 @@
import pulse.search.statistics.FTest;
import pulse.search.statistics.ModelSelectionCriterion;
import pulse.search.statistics.OptimiserStatistic;
+import pulse.search.statistics.Statistic;
import pulse.tasks.logs.Status;
import pulse.tasks.processing.Result;
import pulse.ui.components.PropertyHolderTable;
import pulse.util.InstanceDescriptor;
import pulse.util.PropertyEvent;
import pulse.util.PropertyHolder;
+import pulse.util.UpwardsNavigable;
public class Calculation extends PropertyHolder implements Comparable, Response {
@@ -57,7 +60,7 @@ public Calculation(SearchTask t) {
status = INCOMPLETE;
this.initOptimiser();
setParent(t);
- instanceDescriptor.addListener(() -> initModelCriterion());
+ instanceDescriptor.addListener(() -> initModelCriterion(rs));
}
/**
@@ -66,22 +69,31 @@ public Calculation(SearchTask t) {
* @param c another calculation to be archived.
*/
public Calculation(Calculation c) {
- this.problem = c.problem.copy();
- this.scheme = c.scheme.copy();
- this.rs = c.rs.copy();
- this.os = c.os.copy();
- this.status = c.status;
+ problem = c.problem.copy();
+ scheme = c.scheme.copy();
+ rs = c.rs.copy();
+ os = c.os.copy();
+ status = c.status;
if (c.getResult() != null) {
- this.result = new Result(c.getResult());
+ result = new Result(c.getResult());
}
+ instanceDescriptor.addListener(() -> initModelCriterion(rs));
}
-
+
+ public void conformTo(UpwardsNavigable owner) {
+ problem.setParent(owner);
+ scheme.setParent(owner);
+ rs.setParent(owner);
+ os.setParent(owner);
+ result.setParent(owner);
+ }
+
public void clear() {
this.status = INCOMPLETE;
this.problem = null;
this.scheme = null;
}
-
+
/**
*
* After setting and adopting the {@code problem} by this
@@ -248,7 +260,7 @@ public ModelSelectionCriterion getModelSelectionCriterion() {
public void setOptimiserStatistic(OptimiserStatistic os) {
this.os = os;
os.setParent(this);
- initModelCriterion();
+ initModelCriterion(os);
}
@Override
@@ -263,11 +275,11 @@ public Problem getProblem() {
public void initOptimiser() {
this.setOptimiserStatistic(
instantiate(OptimiserStatistic.class, OptimiserStatistic.getSelectedOptimiserDescriptor()));
- this.initModelCriterion();
+ initModelCriterion(os);
}
- public void initModelCriterion() {
- setModelSelectionCriterion(instanceDescriptor.newInstance(ModelSelectionCriterion.class, os));
+ protected void initModelCriterion(Statistic res) {
+ setModelSelectionCriterion(instanceDescriptor.newInstance(ModelSelectionCriterion.class, res));
}
public DifferenceScheme getScheme() {
@@ -319,27 +331,6 @@ public int compareTo(Calculation arg0) {
return sThis.compareTo(sAnother);
}
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
-
- if (o == null) {
- return false;
- }
-
- if (!(o instanceof Calculation)) {
- return false;
- }
-
- var c = (Calculation) o;
-
- return (os.getStatistic().equals(c.getOptimiserStatistic().getStatistic())
- && rs.getStatistic().equals(c.getModelSelectionCriterion().getStatistic()));
-
- }
-
public static InstanceDescriptor extends ModelSelectionCriterion> getModelSelectionDescriptor() {
return instanceDescriptor;
}
@@ -384,4 +375,37 @@ public double objectiveFunction(GeneralTask task) throws SolverException {
return (double) os.getStatistic().getValue();
}
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 79 * hash + Objects.hashCode(this.problem);
+ hash = 79 * hash + Objects.hashCode(this.scheme);
+ hash = 79 * hash + Objects.hashCode(this.result);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final Calculation other = (Calculation) obj;
+ if (!Objects.equals(this.problem, other.problem)) {
+ return false;
+ }
+ if (!Objects.equals(this.scheme, other.scheme)) {
+ return false;
+ }
+ if (!Objects.equals(this.result, other.result)) {
+ return false;
+ }
+ return true;
+ }
+
}
\ No newline at end of file
diff --git a/src/main/java/pulse/tasks/SearchTask.java b/src/main/java/pulse/tasks/SearchTask.java
index 733a939..91633c8 100644
--- a/src/main/java/pulse/tasks/SearchTask.java
+++ b/src/main/java/pulse/tasks/SearchTask.java
@@ -280,8 +280,7 @@ public void run() {
}
current.getProblem().parameterListChanged(); // get updated list of parameters
- setDefaultOptimiser();
-
+
super.run();
}
@@ -333,8 +332,12 @@ public void storeCalculation() {
}
public void switchTo(Calculation calc) {
- current = calc;
+ current.setParent(null);
+ current.conformTo(null);
+ current = new Calculation(calc);
current.setParent(this);
+ calc.conformTo(calc);
+ current.setStatus(Status.READY);
var e = new TaskRepositoryEvent(TaskRepositoryEvent.State.TASK_MODEL_SWITCH, this.getIdentifier());
fireRepositoryEvent(e);
}
diff --git a/src/main/java/pulse/tasks/logs/AbstractLogger.java b/src/main/java/pulse/tasks/logs/AbstractLogger.java
new file mode 100644
index 0000000..f128837
--- /dev/null
+++ b/src/main/java/pulse/tasks/logs/AbstractLogger.java
@@ -0,0 +1,82 @@
+package pulse.tasks.logs;
+
+import java.util.concurrent.ExecutorService;
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+import javax.swing.JComponent;
+import pulse.tasks.TaskManager;
+import static pulse.tasks.logs.Status.DONE;
+import pulse.util.Descriptive;
+
+public abstract class AbstractLogger implements Descriptive {
+
+ private final ExecutorService updateExecutor;
+
+ public AbstractLogger() {
+ updateExecutor = newSingleThreadExecutor();
+ }
+
+ public synchronized void update() {
+ var task = TaskManager.getManagerInstance().getSelectedTask();
+
+ if (task == null) {
+ return;
+ }
+
+ var log = task.getLog();
+
+ if (log.isStarted()) {
+ post(log.lastEntry());
+ }
+
+ }
+
+ public ExecutorService getUpdateExecutor() {
+ return updateExecutor;
+ }
+
+ public synchronized void callUpdate() {
+ updateExecutor.submit(() -> update());
+ }
+
+ public void postAll() {
+ clear();
+
+ var task = TaskManager.getManagerInstance().getSelectedTask();
+
+ if (task != null) {
+
+ var log = task.getLog();
+
+ if (log.isStarted()) {
+
+ log.getLogEntries().stream().forEach(entry -> post(entry));
+
+ if (task.getStatus() == DONE) {
+ printTimeTaken(log);
+ }
+
+ }
+
+ }
+
+ }
+
+ @Override
+ public String describe() {
+ var task = TaskManager.getManagerInstance().getSelectedTask();
+ return "Log" + (task == null ? "" : "_" + task.getIdentifier().getValue());
+ }
+
+ public abstract JComponent getGUIComponent();
+
+ public abstract void printTimeTaken(Log log);
+
+ public abstract void post(LogEntry logEntry);
+
+ public abstract void post(String text);
+
+ public abstract void clear();
+
+ public abstract boolean isEmpty();
+
+}
diff --git a/src/main/java/pulse/tasks/logs/DataLogEntry.java b/src/main/java/pulse/tasks/logs/DataLogEntry.java
index 2fad022..94b8774 100644
--- a/src/main/java/pulse/tasks/logs/DataLogEntry.java
+++ b/src/main/java/pulse/tasks/logs/DataLogEntry.java
@@ -5,6 +5,8 @@
import pulse.math.Parameter;
import pulse.math.ParameterIdentifier;
import pulse.properties.NumericProperties;
+import static pulse.properties.NumericProperties.def;
+import static pulse.properties.NumericPropertyKeyword.OBJECTIVE_FUNCTION;
import pulse.tasks.SearchTask;
import pulse.tasks.TaskManager;
@@ -54,10 +56,19 @@ public DataLogEntry(SearchTask task) {
private void fill() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
var task = TaskManager.getManagerInstance().getTask(getIdentifier());
entry = task.searchVector().getParameters();
+ //iteration
var pval = task.getIterativeState().getIteration();
var pid = new Parameter(new ParameterIdentifier(pval.getType()));
- pid.setValue( (int) pval.getValue() );
+ pid.setValue((int) pval.getValue());
+ //cost
+ var costId = new Parameter(new ParameterIdentifier(OBJECTIVE_FUNCTION));
+ var costval = task.getIterativeState().getCost();
+ //
entry.add(0, pid);
+ if (NumericProperties.isValueSensible(def(OBJECTIVE_FUNCTION), costval)) {
+ costId.setValue(costval);
+ entry.add(costId);
+ }
}
public List getData() {
@@ -90,15 +101,15 @@ public String toString() {
var def = NumericProperties.def(p.getIdentifier().getKeyword());
boolean b = def.getValue() instanceof Integer;
Number val;
- if(b) {
+ if (b) {
val = (int) Math.rint(p.getApparentValue());
- } else{
+ } else {
val = p.getApparentValue();
}
def.setValue(val);
sb.append(def.getAbbreviation(false));
int index = p.getIdentifier().getIndex();
- if(index > 0) {
+ if (index > 0) {
sb.append(" - ").append(index);
}
sb.append("<");
@@ -116,4 +127,4 @@ public String toString() {
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/tasks/logs/Log.java b/src/main/java/pulse/tasks/logs/Log.java
index 5b51953..21a32df 100644
--- a/src/main/java/pulse/tasks/logs/Log.java
+++ b/src/main/java/pulse/tasks/logs/Log.java
@@ -1,6 +1,8 @@
package pulse.tasks.logs;
import java.time.LocalTime;
+import static java.time.temporal.ChronoUnit.MILLIS;
+import static java.time.temporal.ChronoUnit.SECONDS;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -24,7 +26,7 @@ public class Log extends Group {
private LocalTime end;
private final Identifier id;
private final List listeners;
- private static boolean verbose = false;
+ private static boolean graphical = true;
/**
* Creates a {@code Log} for this {@code task} that will automatically store
@@ -48,7 +50,7 @@ public Log(SearchTask task) {
/**
* Do these actions each time data has been collected for this task.
*/
- if (task.getStatus() != Status.INCOMPLETE && verbose) {
+ if (task.getStatus() != Status.INCOMPLETE) {
logEntries.add(le);
notifyListeners(le);
}
@@ -105,7 +107,7 @@ public final Identifier getIdentifier() {
* @return {@code true} if the start time is not {@code null}
*/
public boolean isStarted() {
- return start != null;
+ return logEntries.size() > 0;
}
/**
@@ -173,18 +175,29 @@ public LogEntry lastEntry() {
*
* @return {@code true} if the verbose flag is on
*/
- public static boolean isVerbose() {
- return verbose;
+ public static boolean isGraphicalLog() {
+ return graphical;
}
/**
* Sets the verbose flag to {@code verbose}
*
* @param verbose the new value of the flag
- * @see isVerbose()
+ * @see #isGraphicalLog()
*/
- public static void setVerbose(boolean verbose) {
- Log.verbose = verbose;
+ public static void setGraphicalLog(boolean verbose) {
+ Log.graphical = verbose;
+ }
+
+ /**
+ * Time taken where the first array element contains seconds [0] and the second contains milliseconds [1].
+ * @return an array of long values that sum um to the time taken to process a task
+ */
+
+ public long[] timeTaken() {
+ var seconds = SECONDS.between(getStart(), getEnd());
+ var ms = MILLIS.between(getStart(), getEnd()) - 1000L * seconds;
+ return new long[] {seconds, ms};
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/tasks/logs/LogEntry.java b/src/main/java/pulse/tasks/logs/LogEntry.java
index 7841a91..f311fd1 100644
--- a/src/main/java/pulse/tasks/logs/LogEntry.java
+++ b/src/main/java/pulse/tasks/logs/LogEntry.java
@@ -3,6 +3,7 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Objects;
+import pulse.Response;
import pulse.tasks.Identifier;
import pulse.tasks.SearchTask;
@@ -19,9 +20,10 @@
*/
public class LogEntry {
- private Identifier identifier;
- private LocalTime time;
-
+ private final Identifier identifier;
+ private final LocalTime time;
+ private final LogEntry previous;
+
/**
*
* Creates a {@code LogEntry} from this {@code SearchTask}. The data of the
@@ -34,6 +36,17 @@ public LogEntry(SearchTask t) {
Objects.requireNonNull(t, Messages.getString("LogEntry.NullTaskError"));
time = LocalDateTime.now().toLocalTime();
identifier = t.getIdentifier();
+ var list = t.getLog().getLogEntries();
+ if(list != null && !list.isEmpty()) {
+ previous = list.get(list.size() - 1);
+ }
+ else {
+ previous = null;
+ }
+ }
+
+ public LogEntry getPreviousEntry() {
+ return previous;
}
public Identifier getIdentifier() {
@@ -44,4 +57,4 @@ public LocalTime getTime() {
return time;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/tasks/processing/Buffer.java b/src/main/java/pulse/tasks/processing/Buffer.java
index e3a1684..90ef5bd 100644
--- a/src/main/java/pulse/tasks/processing/Buffer.java
+++ b/src/main/java/pulse/tasks/processing/Buffer.java
@@ -8,10 +8,14 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.stream.Stream;
+import org.apache.commons.math3.stat.regression.SimpleRegression;
+import pulse.math.ParameterIdentifier;
import pulse.math.ParameterVector;
import pulse.properties.NumericProperty;
import pulse.properties.NumericPropertyKeyword;
+import static pulse.properties.NumericPropertyKeyword.OBJECTIVE_FUNCTION;
import pulse.properties.Property;
import pulse.search.GeneralTask;
import pulse.util.PropertyHolder;
@@ -48,7 +52,7 @@ public ParameterVector[] getData() {
/*
* Re-inits the storage.
*/
- public void init() {
+ public final void init() {
this.data = new ParameterVector[size];
statistic = new double[size];
}
@@ -105,11 +109,17 @@ public double average(NumericPropertyKeyword index) {
double av = 0;
- for (ParameterVector v : data) {
- av += v.getParameterValue(index, 0);
+ if (index == OBJECTIVE_FUNCTION) {
+ av = Arrays.stream(statistic).average().getAsDouble();
+ } else {
+
+ for (ParameterVector v : data) {
+ av += v.getParameterValue(index, 0);
+ }
+ av /= data.length;
}
- return av / data.length;
+ return av;
}
diff --git a/src/main/java/pulse/ui/ColorGenerator.java b/src/main/java/pulse/ui/ColorGenerator.java
new file mode 100644
index 0000000..2e2388d
--- /dev/null
+++ b/src/main/java/pulse/ui/ColorGenerator.java
@@ -0,0 +1,45 @@
+package pulse.ui;
+
+import java.awt.Color;
+import static java.awt.Color.BLUE;
+import static java.awt.Color.GREEN;
+import static java.awt.Color.RED;
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class ColorGenerator {
+
+ private Color a, b, c;
+
+ public ColorGenerator() {
+ a = RED;
+ b = GREEN;
+ c = BLUE;
+ }
+
+ public Color[] random(int number) {
+ var list = new ArrayList();
+ for(int i = 0; i < number; i++) {
+ list.add(sample(i/(double)(number - 1)));
+ }
+ //Collections.shuffle(list);
+ return list.toArray(new Color[list.size()]);
+ }
+
+ public Color sample(double seed) {
+ return seed < 0.5 ?
+ mix(a, b, (float) (seed*2))
+ : mix(b, c,(float)((seed-0.5)*2));
+ }
+
+ private static Color mix(Color a, Color b, float ratio) {
+ float[] aRgb = a.getRGBComponents(null);
+ float[] bRgb = b.getRGBComponents(null);
+ float[] cRgb = new float[3];
+ for(int i = 0; i < cRgb.length; i++) {
+ cRgb[i] = aRgb[i] * (1.0f - ratio) + bRgb[i] * ratio;
+ }
+ return new Color(cRgb[0], cRgb[1], cRgb[2]);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/Launcher.java b/src/main/java/pulse/ui/Launcher.java
index de97832..ee238ac 100644
--- a/src/main/java/pulse/ui/Launcher.java
+++ b/src/main/java/pulse/ui/Launcher.java
@@ -17,8 +17,7 @@
import javax.swing.JOptionPane;
import javax.swing.UIManager;
-import com.alee.laf.WebLookAndFeel;
-import com.alee.skin.dark.WebDarkSkin;
+import com.formdev.flatlaf.FlatDarkLaf;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -65,9 +64,10 @@ public static void main(String[] args) {
splashScreen();
- WebLookAndFeel.install(WebDarkSkin.class);
+ //WebLookAndFeel.install(WebDarkSkin.class);
+ FlatDarkLaf.setup();
try {
- UIManager.setLookAndFeel(new WebLookAndFeel());
+ UIManager.setLookAndFeel(new FlatDarkLaf());
} catch (Exception ex) {
System.err.println("Failed to initialize LaF");
}
diff --git a/src/main/java/pulse/ui/components/AuxPlotter.java b/src/main/java/pulse/ui/components/AuxPlotter.java
index 8150c4c..602a3d6 100644
--- a/src/main/java/pulse/ui/components/AuxPlotter.java
+++ b/src/main/java/pulse/ui/components/AuxPlotter.java
@@ -1,58 +1,85 @@
package pulse.ui.components;
+import java.awt.Color;
import java.awt.Font;
+import javax.swing.JLabel;
import javax.swing.UIManager;
+import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.CombinedDomainXYPlot;
+import static org.jfree.chart.plot.PlotOrientation.VERTICAL;
import org.jfree.chart.plot.XYPlot;
public abstract class AuxPlotter {
-
+
private ChartPanel chartPanel;
private JFreeChart chart;
private XYPlot plot;
-
+
+ public AuxPlotter() {
+ //empty
+ }
+
public AuxPlotter(String xLabel, String yLabel) {
- createChart(xLabel, yLabel);
- chart.setBackgroundPaint(UIManager.getColor("Panel.background"));
+ setChart( ChartFactory.createScatterPlot("", xLabel, yLabel, null, VERTICAL, true, true, false) );
+
+ setPlot( chart.getXYPlot() );
+ chart.removeLegend();
- plot = chart.getXYPlot();
setFonts();
-
- chart.removeLegend();
- chartPanel = new ChartPanel(chart);
}
-
- public void setFonts() {
- var fontLabel = new Font("Arial", Font.PLAIN, 20);
- var fontTicks = new Font("Arial", Font.PLAIN, 16);
- var plot = getPlot();
- plot.getDomainAxis().setLabelFont(fontLabel);
- plot.getDomainAxis().setTickLabelFont(fontTicks);
- plot.getRangeAxis().setLabelFont(fontLabel);
- plot.getRangeAxis().setTickLabelFont(fontTicks);
+
+ public final void setFonts() {
+ var jlabel = new JLabel();
+ var label = jlabel.getFont().deriveFont(20f);
+ var ticks = jlabel.getFont().deriveFont(16f);
+ chart.getTitle().setFont(jlabel.getFont().deriveFont(20f));
+
+ if (plot instanceof CombinedDomainXYPlot) {
+ var combinedPlot = (CombinedDomainXYPlot) plot;
+ combinedPlot.getSubplots().stream().forEach(sp -> setFontsForPlot((XYPlot)sp, label, ticks));
+ } else {
+ setFontsForPlot(plot, label, ticks);
+ }
+
}
-
- public abstract void createChart(String xLabel, String yLabel);
-
+
+ private void setFontsForPlot(XYPlot p, Font label, Font ticks) {
+ var foreColor = UIManager.getColor("Label.foreground");
+ var domainAxis = p.getDomainAxis();
+ Chart.setAxisFontColor(domainAxis, foreColor);
+ var rangeAxis = p.getRangeAxis();
+ Chart.setAxisFontColor(rangeAxis, foreColor);
+ }
+
public abstract void plot(T t);
-
- public ChartPanel getChartPanel() {
+
+ public final ChartPanel getChartPanel() {
return chartPanel;
}
-
- public JFreeChart getChart() {
+
+ public final JFreeChart getChart() {
return chart;
}
-
- public XYPlot getPlot() {
+
+ public final XYPlot getPlot() {
return plot;
}
-
- public void setChart(JFreeChart chart) {
+
+ public final void setPlot(XYPlot plot) {
+ this.plot = plot;
+ plot.setBackgroundPaint(chart.getBackgroundPaint());
+ }
+
+ public final void setChart(JFreeChart chart) {
this.chart = chart;
+ var color = UIManager.getLookAndFeelDefaults().getColor("TextPane.background");
+ chart.setBackgroundPaint(color);
+ chartPanel = new ChartPanel(chart);
+ this.plot = chart.getXYPlot();
}
-
-}
+
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/components/CalculationTable.java b/src/main/java/pulse/ui/components/CalculationTable.java
index 95c4ab1..4ebf483 100644
--- a/src/main/java/pulse/ui/components/CalculationTable.java
+++ b/src/main/java/pulse/ui/components/CalculationTable.java
@@ -8,6 +8,7 @@
import java.util.concurrent.Executors;
import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.TableCellRenderer;
@@ -50,10 +51,7 @@ public CalculationTable() {
var instance = TaskManager.getManagerInstance();
instance.addTaskRepositoryListener(e -> {
- if (e.getState() == TaskRepositoryEvent.State.TASK_MODEL_SWITCH) {
- var t = instance.getTask(e.getId());
- identifySelection(t);
- } else if (e.getState() == TaskRepositoryEvent.State.TASK_CRITERION_SWITCH) {
+ if (e.getState() == TaskRepositoryEvent.State.TASK_CRITERION_SWITCH) {
update(TaskManager.getManagerInstance().getSelectedTask());
}
@@ -84,7 +82,9 @@ public void initListeners() {
lsm.addListSelectionListener((ListSelectionEvent e) -> {
var task = TaskManager.getManagerInstance().getSelectedTask();
var id = convertRowIndexToModel(this.getSelectedRow());
- if (!lsm.getValueIsAdjusting() && id > -1 && id < task.getStoredCalculations().size()) {
+ if (!lsm.getValueIsAdjusting()
+ && id > -1
+ && id < task.getStoredCalculations().size()) {
plotExecutor.submit(() -> {
task.switchTo(task.getStoredCalculations().get(id));
diff --git a/src/main/java/pulse/ui/components/Chart.java b/src/main/java/pulse/ui/components/Chart.java
index 68dda2d..7fe372e 100644
--- a/src/main/java/pulse/ui/components/Chart.java
+++ b/src/main/java/pulse/ui/components/Chart.java
@@ -26,6 +26,7 @@
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYTitleAnnotation;
+import org.jfree.chart.axis.Axis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
@@ -81,7 +82,7 @@ public Chart() {
final TaskManager instance = TaskManager.getManagerInstance();
chart.removeLegend();
- chart.setBackgroundPaint(UIManager.getColor("Panel.background"));
+ chart.setBackgroundPaint(UIManager.getColor("TextPane.background"));
chartPanel = new ChartPanel(chart) {
@Override
@@ -146,16 +147,18 @@ public double xCoord(MouseEvent e) {
}
private void setFonts() {
- var fontLabel = new Font("Arial", Font.PLAIN, 20);
- var fontTicks = new Font("Arial", Font.PLAIN, 14);
- plot.getDomainAxis().setLabelFont(fontLabel);
- plot.getDomainAxis().setTickLabelFont(fontTicks);
- plot.getRangeAxis().setLabelFont(fontLabel);
- plot.getRangeAxis().setTickLabelFont(fontTicks);
+ var foreColor = UIManager.getColor("Label.foreground");
+ setAxisFontColor(plot.getDomainAxis(), foreColor);
+ setAxisFontColor(plot.getRangeAxis(), foreColor);
+ }
+
+ public static void setAxisFontColor(Axis axis, Color color) {
+ axis.setLabelPaint(color);
+ axis.setTickLabelPaint(color);
}
private void setBackgroundAndGrid() {
- // plot.setBackgroundPaint(UIManager.getColor("Panel.background"));
+ plot.setBackgroundPaint(UIManager.getColor("TextPane.background"));
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(GRAY);
diff --git a/src/main/java/pulse/ui/components/GraphicalLogPane.java b/src/main/java/pulse/ui/components/GraphicalLogPane.java
new file mode 100644
index 0000000..82f8424
--- /dev/null
+++ b/src/main/java/pulse/ui/components/GraphicalLogPane.java
@@ -0,0 +1,98 @@
+package pulse.ui.components;
+
+import javax.swing.JComponent;
+import javax.swing.JScrollPane;
+import javax.swing.ScrollPaneConstants;
+import static pulse.properties.NumericPropertyKeyword.ITERATION;
+import pulse.tasks.TaskManager;
+import pulse.tasks.listeners.TaskRepositoryEvent;
+import pulse.tasks.logs.AbstractLogger;
+import pulse.tasks.logs.DataLogEntry;
+import pulse.tasks.logs.Log;
+import pulse.tasks.logs.LogEntry;
+import static pulse.tasks.logs.Status.DONE;
+
+@SuppressWarnings("serial")
+public class GraphicalLogPane extends AbstractLogger {
+
+ private final LogChart chart;
+ private final JScrollPane pane;
+
+ public GraphicalLogPane() {
+ pane = new JScrollPane();
+ pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ chart = new LogChart();
+ pane.setViewportView(chart.getChartPanel());
+ TaskManager.getManagerInstance().addTaskRepositoryListener( e -> {
+ if(e.getState() == TaskRepositoryEvent.State.TASK_SUBMITTED) {
+ chart.clear();
+ }
+ });
+ }
+
+ @Override
+ public JComponent getGUIComponent() {
+ return pane;
+ }
+
+ @Override
+ public void printTimeTaken(Log log) {
+ long[] time = log.timeTaken();
+ StringBuilder sb = new StringBuilder("Finished in ");
+ sb.append(time[0]).append(" s ").append(time[1]).append(" ms.");
+ }
+
+ @Override
+ public void post(LogEntry logEntry) {
+ if(logEntry instanceof DataLogEntry) {
+ var dle = (DataLogEntry) logEntry;
+ double iteration = dle.getData().stream()
+ .filter(p -> p.getIdentifier().getKeyword() == ITERATION)
+ .findAny().get().getApparentValue();
+ chart.changeAxis(true);
+ chart.plot((DataLogEntry)logEntry, iteration);
+ }
+ }
+
+ @Override
+ public void postAll() {
+ clear();
+
+ var task = TaskManager.getManagerInstance().getSelectedTask();
+
+ if (task != null) {
+
+ var log = task.getLog();
+
+ if (log.isStarted()) {
+
+ chart.clear();
+ chart.changeAxis(false);
+ chart.plot(log);
+
+ if (task.getStatus() == DONE) {
+ printTimeTaken(log);
+ }
+
+ }
+
+ }
+
+ }
+
+ @Override
+ public void post(String text) {
+ //not supported
+ }
+
+ @Override
+ public void clear() {
+ chart.clear();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/components/LogChart.java b/src/main/java/pulse/ui/components/LogChart.java
new file mode 100644
index 0000000..ba40ae4
--- /dev/null
+++ b/src/main/java/pulse/ui/components/LogChart.java
@@ -0,0 +1,220 @@
+package pulse.ui.components;
+
+import static java.util.Objects.requireNonNull;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import static java.awt.Color.WHITE;
+import static java.awt.Color.black;
+import java.awt.Dimension;
+import java.time.Duration;
+import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.swing.SwingUtilities;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.annotations.XYTitleAnnotation;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.axis.NumberTickUnit;
+import org.jfree.chart.block.BlockBorder;
+import org.jfree.chart.plot.CombinedDomainXYPlot;
+import org.jfree.chart.plot.Plot;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.chart.title.LegendTitle;
+import org.jfree.chart.ui.RectangleAnchor;
+import org.jfree.chart.ui.RectangleEdge;
+import org.jfree.data.Range;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+import pulse.Response;
+import pulse.math.ParameterIdentifier;
+
+import static pulse.properties.NumericPropertyKeyword.ITERATION;
+import pulse.tasks.SearchTask;
+import pulse.tasks.TaskManager;
+import pulse.tasks.logs.DataLogEntry;
+import pulse.tasks.logs.Log;
+import pulse.tasks.logs.StateEntry;
+import pulse.tasks.logs.Status;
+import pulse.tasks.processing.Buffer;
+import pulse.ui.ColorGenerator;
+
+public class LogChart extends AuxPlotter {
+
+ private final Map plots;
+ private Color[] colors;
+ private static final ColorGenerator cg = new ColorGenerator();
+ public final static int HEIGHT_FACTOR = 75;
+ public final static int MARGIN = 10;
+
+ public LogChart() {
+ var plot = new CombinedDomainXYPlot(new NumberAxis("Iteration"));
+ plot.setGap(10.0);
+ plot.setOrientation(PlotOrientation.VERTICAL);
+ var chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, true);
+ setChart(chart);
+ plots = new HashMap<>();
+ getChart().removeLegend();
+ }
+
+ public final void clear() {
+ var p = (CombinedDomainXYPlot) getPlot();
+ if (p != null) {
+ if (p.getDomainAxis() != null) {
+ p.getDomainAxis().setAutoRange(true);
+ }
+ plots.values().stream().forEach(pp -> p.remove(pp));
+ }
+ plots.clear();
+ colors = new Color[0];
+ }
+
+ private void setLegendTitle(Plot plot) {
+ var lt = new LegendTitle(plot);
+ lt.setBackgroundPaint(new Color(200, 200, 255, 100));
+ lt.setFrame(new BlockBorder(black));
+ lt.setPosition(RectangleEdge.RIGHT);
+ var ta = new XYTitleAnnotation(0.0, 0.8, lt, RectangleAnchor.LEFT);
+ ta.setMaxWidth(0.58);
+ ((XYPlot) plot).addAnnotation(ta);
+ }
+
+ public final void add(ParameterIdentifier key, int no) {
+ var plot = new XYPlot();
+ var axis = new NumberAxis();
+ axis.setAutoRangeIncludesZero(false);
+ plot.setRangeAxis(axis);
+
+ plot.setBackgroundPaint(getChart().getBackgroundPaint());
+
+ plots.put(key, plot);
+ ((CombinedDomainXYPlot) getPlot()).add(plot);
+
+ int height = HEIGHT_FACTOR * plots.size();
+ int width = getChartPanel().getParent().getWidth() - MARGIN;
+ getChartPanel().setPreferredSize(new Dimension(width, height));
+ getChartPanel().revalidate();
+
+ var dataset = new XYSeriesCollection();
+ var series = new XYSeries(key.toString());
+
+ dataset.addSeries(series);
+ dataset.addSeries(new XYSeries("Running average"));
+ plot.setDataset(dataset);
+ setLegendTitle(plot);
+
+ setRenderer(plot, colors[no]);
+ setFonts();
+ }
+
+ private void setRenderer(XYPlot plt, Color clr) {
+ var renderer = new XYLineAndShapeRenderer(true, false);
+ renderer.setSeriesPaint(0, clr);
+ renderer.setSeriesPaint(1, WHITE);
+ var dashed = new BasicStroke(1.0f, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_MITER, 10.0f, new float[]{10.0f}, 0.0f);
+ renderer.setSeriesStroke(1, dashed);
+ renderer.setSeriesVisibleInLegend(1, Boolean.FALSE);
+ plt.setRenderer(renderer);
+ }
+
+ public void changeAxis(boolean iterationMode) {
+ var domainAxis = (NumberAxis) getPlot().getDomainAxis();
+ domainAxis.setLabel(iterationMode ? "Iteration" : "Time (ms)");
+ domainAxis.setAutoRange(!iterationMode);
+ if (iterationMode) {
+ domainAxis.setTickUnit(new NumberTickUnit(1));
+ } else {
+ domainAxis.setAutoTickUnitSelection(true);
+ }
+ }
+
+ @Override
+ public void plot(Log l) {
+ requireNonNull(l);
+
+ List startTimes = l.getLogEntries().stream()
+ .filter(le -> le instanceof DataLogEntry && le.getPreviousEntry() instanceof StateEntry)
+ .map(entry -> entry.getTime()).collect(Collectors.toList());
+
+ if (!startTimes.isEmpty()) {
+ var recentStart = startTimes.get(startTimes.size() - 1);
+ l.getLogEntries().stream().filter(le -> le.getTime().isAfter(recentStart))
+ .filter(e -> e instanceof DataLogEntry).forEach(dle
+ -> plot((DataLogEntry) dle,
+ Duration.between(recentStart, dle.getTime()).toMillis()));
+ }
+
+ }
+
+ private static void adjustRange(XYPlot pl, int iteration, int bufSize) {
+ int lower = (iteration / bufSize) * bufSize;
+
+ var domainAxis = pl.getDomainAxis();
+ var r = domainAxis.getRange();
+ var newR = new Range(lower, lower + bufSize);
+
+ if (!r.equals(newR) && iteration > lower) {
+ ((XYPlot) pl).getDomainAxis().setRange(lower, lower + bufSize);
+ }
+ }
+
+ public final void plot(DataLogEntry dle, double iterationOrTime) {
+ requireNonNull(dle);
+
+ var data = dle.getData();
+ int size = data.size();
+
+ if (colors == null || colors.length < size) {
+ colors = cg.random(size - 1);
+ }
+
+ SearchTask task = TaskManager.getManagerInstance().getTask(dle.getIdentifier());
+ Buffer buf = task.getBuffer();
+ final int bufSize = buf.getData().length;
+
+ for (int i = 0, j = 0; i < size; i++) {
+ var p = data.get(i);
+ var np = p.getIdentifier();
+
+ if (np.getKeyword() == ITERATION) {
+ continue;
+ }
+
+ double value = p.getApparentValue();
+
+ if (!plots.containsKey(np)) {
+ add(np, j++);
+ }
+
+ Plot pl = plots.get(np);
+
+ var dataset = (XYSeriesCollection) ((XYPlot) pl).getDataset();
+ XYSeries series = (XYSeries) dataset.getSeries(0);
+ series.add(iterationOrTime, value);
+
+ if (task.getStatus() == Status.IN_PROGRESS) {
+
+ XYSeries runningAverage = dataset.getSeries(1);
+ if (iterationOrTime > buf.getData().length - 1) {
+ runningAverage.add(iterationOrTime, buf.average(np.getKeyword()));
+ }
+
+ SwingUtilities.invokeLater(() -> adjustRange((XYPlot) pl, (int) iterationOrTime, bufSize));
+
+ } else {
+ var domainAxis = ((XYPlot) pl).getDomainAxis();
+ domainAxis.setAutoRange(true);
+ }
+
+ }
+
+ }
+
+}
diff --git a/src/main/java/pulse/ui/components/LogPane.java b/src/main/java/pulse/ui/components/LogPane.java
deleted file mode 100644
index 5af4215..0000000
--- a/src/main/java/pulse/ui/components/LogPane.java
+++ /dev/null
@@ -1,136 +0,0 @@
-package pulse.ui.components;
-
-import static java.lang.System.err;
-import static java.time.temporal.ChronoUnit.MILLIS;
-import static java.time.temporal.ChronoUnit.SECONDS;
-import static java.util.concurrent.Executors.newSingleThreadExecutor;
-import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE;
-import static pulse.tasks.logs.Status.DONE;
-import static pulse.ui.Messages.getString;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-
-import javax.swing.JEditorPane;
-import javax.swing.text.BadLocationException;
-import javax.swing.text.DefaultCaret;
-import javax.swing.text.html.HTMLDocument;
-import javax.swing.text.html.HTMLEditorKit;
-
-import pulse.tasks.TaskManager;
-import pulse.tasks.logs.Log;
-import pulse.tasks.logs.LogEntry;
-import pulse.util.Descriptive;
-
-@SuppressWarnings("serial")
-public class LogPane extends JEditorPane implements Descriptive {
-
- private ExecutorService updateExecutor = newSingleThreadExecutor();
-
- public LogPane() {
- super();
- setContentType("text/html");
- setEditable(false);
- var c = (DefaultCaret) getCaret();
- c.setUpdatePolicy(ALWAYS_UPDATE);
- }
-
- private void post(LogEntry logEntry) {
- post(logEntry.toString());
- }
-
- /*
- private void postError(String text) {
- var sb = new StringBuilder();
- sb.append(getString("DataLogEntry.FontTagError"));
- sb.append(text);
- sb.append(getString("DataLogEntry.FontTagClose"));
- post(sb.toString());
- }*/
- private void post(String text) {
-
- final var doc = (HTMLDocument) getDocument();
- final var kit = (HTMLEditorKit) this.getEditorKit();
- try {
- kit.insertHTML(doc, doc.getLength(), text, 0, 0, null);
- } catch (BadLocationException e) {
- err.println(getString("LogPane.InsertError")); //$NON-NLS-1$
- e.printStackTrace();
- } catch (IOException e) {
- err.println(getString("LogPane.PrintError")); //$NON-NLS-1$
- e.printStackTrace();
- }
-
- }
-
- public void printTimeTaken(Log log) {
- var seconds = SECONDS.between(log.getStart(), log.getEnd());
- var ms = MILLIS.between(log.getStart(), log.getEnd()) - 1000L * seconds;
- var sb = new StringBuilder();
- sb.append(getString("LogPane.TimeTaken")); //$NON-NLS-1$
- sb.append(seconds + getString("LogPane.Seconds")); //$NON-NLS-1$
- sb.append(ms + getString("LogPane.Milliseconds")); //$NON-NLS-1$
- post(sb.toString());
- }
-
- public synchronized void callUpdate() {
- updateExecutor.submit(() -> update());
- }
-
- public void printAll() {
- clear();
-
- var task = TaskManager.getManagerInstance().getSelectedTask();
-
- if (task != null) {
-
- var log = task.getLog();
-
- if (log.isStarted()) {
-
- log.getLogEntries().stream().forEach(entry -> post(entry));
-
- if (task.getStatus() == DONE) {
- printTimeTaken(log);
- }
-
- }
-
- }
-
- }
-
- private synchronized void update() {
- var task = TaskManager.getManagerInstance().getSelectedTask();
-
- if (task == null) {
- return;
- }
-
- var log = task.getLog();
-
- if (!log.isStarted()) {
- return;
- }
-
- post(log.lastEntry());
- }
-
- public void clear() {
- try {
- getDocument().remove(0, getDocument().getLength());
- } catch (BadLocationException e) {
- e.printStackTrace();
- }
- }
-
- public ExecutorService getUpdateExecutor() {
- return updateExecutor;
- }
-
- @Override
- public String describe() {
- return "Log_" + TaskManager.getManagerInstance().getSelectedTask().getIdentifier().getValue();
- }
-
-}
diff --git a/src/main/java/pulse/ui/components/PulseChart.java b/src/main/java/pulse/ui/components/PulseChart.java
index bb33646..5b4151a 100644
--- a/src/main/java/pulse/ui/components/PulseChart.java
+++ b/src/main/java/pulse/ui/components/PulseChart.java
@@ -4,13 +4,11 @@
import static java.awt.Color.black;
import static java.awt.Font.PLAIN;
import static java.util.Objects.requireNonNull;
-import static org.jfree.chart.plot.PlotOrientation.VERTICAL;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
-import org.jfree.chart.ChartFactory;
import org.jfree.chart.annotations.XYTitleAnnotation;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.renderer.xy.XYDifferenceRenderer;
@@ -41,16 +39,11 @@ private void setRenderer() {
getPlot().setRenderer(rendererPulse);
}
- @Override
- public void createChart(String xLabel, String yLabel) {
- setChart(ChartFactory.createScatterPlot("", xLabel, yLabel, null, VERTICAL, true, true, false));
- }
-
private void setLegendTitle() {
var plot = getPlot();
var lt = new LegendTitle(plot);
lt.setItemFont(new Font("Dialog", PLAIN, 16));
- //lt.setBackgroundPaint(new Color(200, 200, 255, 100));
+ lt.setBackgroundPaint(new Color(200, 200, 255, 100));
lt.setFrame(new BlockBorder(black));
lt.setPosition(RectangleEdge.RIGHT);
var ta = new XYTitleAnnotation(0.5, 0.2, lt, RectangleAnchor.CENTER);
@@ -68,8 +61,8 @@ public void plot(Calculation c) {
var pulseDataset = new XYSeriesCollection();
- pulseDataset.addSeries(series(problem.getPulse(), c.getScheme().getGrid().getTimeStep(),
- problem.getProperties().timeFactor(), startTime));
+ pulseDataset.addSeries(series(problem.getPulse(), c.getScheme().getGrid().getTimeStep()/20.0,
+ problem.getProperties().characteristicTime(), startTime));
getPlot().setDataset(0, pulseDataset);
}
@@ -81,8 +74,8 @@ private static XYSeries series(Pulse pulse, double dx, double timeFactor, double
double timeLimit = pulseShape.getPulseWidth();
double x = startTime/timeFactor;
- series.add(TO_MILLIS * (startTime - dx * timeFactor / 10.), 0.0);
- series.add(TO_MILLIS * (startTime + timeFactor*(timeLimit + dx / 10.)), 0.0);
+ series.add(TO_MILLIS * (startTime - dx * timeFactor / 100.), 0.0);
+ series.add(TO_MILLIS * (startTime + timeFactor*(timeLimit + dx / 100.)), 0.0);
for (int i = 0, numPoints = (int) (timeLimit/dx); i < numPoints; i++) {
series.add(x * timeFactor * TO_MILLIS, pulseShape.evaluateAt(x - startTime/timeFactor));
diff --git a/src/main/java/pulse/ui/components/ResidualsChart.java b/src/main/java/pulse/ui/components/ResidualsChart.java
index 7a78ee2..7543707 100644
--- a/src/main/java/pulse/ui/components/ResidualsChart.java
+++ b/src/main/java/pulse/ui/components/ResidualsChart.java
@@ -1,9 +1,8 @@
package pulse.ui.components;
import static java.util.Objects.requireNonNull;
-import static org.jfree.chart.plot.PlotOrientation.VERTICAL;
-
import org.jfree.chart.ChartFactory;
+import static org.jfree.chart.plot.PlotOrientation.VERTICAL;
import org.jfree.data.statistics.HistogramDataset;
import org.jfree.data.statistics.HistogramType;
@@ -14,15 +13,13 @@ public class ResidualsChart extends AuxPlotter {
private int binCount;
public ResidualsChart(String xLabel, String yLabel) {
- super(xLabel, yLabel);
- binCount = 32;
- }
-
- @Override
- public void createChart(String xLabel, String yLabel) {
setChart(ChartFactory.createHistogram("", xLabel, yLabel, null, VERTICAL, true, true, false));
+ setPlot(getChart().getXYPlot());
+ getChart().removeLegend();
+ setFonts();
+ binCount = 32;
}
-
+
@Override
public void plot(ResidualStatistic stat) {
requireNonNull(stat);
diff --git a/src/main/java/pulse/ui/components/TaskBox.java b/src/main/java/pulse/ui/components/TaskBox.java
index 9be85ed..13b8445 100644
--- a/src/main/java/pulse/ui/components/TaskBox.java
+++ b/src/main/java/pulse/ui/components/TaskBox.java
@@ -1,6 +1,5 @@
package pulse.ui.components;
-import static java.awt.Color.WHITE;
import static java.awt.event.ItemEvent.SELECTED;
import static pulse.ui.Messages.getString;
@@ -46,11 +45,10 @@ public TaskBox() {
});
}
- public void init() {
+ public final void init() {
setMaximumSize(new Dimension(32767, 24));
setMinimumSize(new Dimension(250, 20));
setToolTipText(getString("TaskBox.DefaultText")); //$NON-NLS-1$
- setBackground(WHITE);
}
}
diff --git a/src/main/java/pulse/ui/components/TextLogPane.java b/src/main/java/pulse/ui/components/TextLogPane.java
new file mode 100644
index 0000000..f1b7dfc
--- /dev/null
+++ b/src/main/java/pulse/ui/components/TextLogPane.java
@@ -0,0 +1,85 @@
+package pulse.ui.components;
+
+import pulse.tasks.logs.AbstractLogger;
+import static java.lang.System.err;
+import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE;
+import static pulse.ui.Messages.getString;
+
+import java.io.IOException;
+import javax.swing.JComponent;
+
+import javax.swing.JEditorPane;
+import javax.swing.JScrollPane;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.DefaultCaret;
+import javax.swing.text.html.HTMLDocument;
+import javax.swing.text.html.HTMLEditorKit;
+
+import pulse.tasks.logs.Log;
+import pulse.tasks.logs.LogEntry;
+
+@SuppressWarnings("serial")
+public class TextLogPane extends AbstractLogger {
+
+ private final JEditorPane editor;
+ private final JScrollPane pane;
+
+ public TextLogPane() {
+ editor = new JEditorPane();
+ editor.setContentType("text/html");
+ editor.setEditable(false);
+ ( (DefaultCaret) editor.getCaret() ).setUpdatePolicy(ALWAYS_UPDATE);
+ pane = new JScrollPane();
+ pane.setViewportView(editor);
+ }
+
+ @Override
+ public void post(LogEntry logEntry) {
+ post(logEntry.toString());
+ }
+
+ @Override
+ public void post(String text) {
+
+ final var doc = (HTMLDocument) editor.getDocument();
+ final var kit = (HTMLEditorKit) editor.getEditorKit();
+ try {
+ kit.insertHTML(doc, doc.getLength(), text, 0, 0, null);
+ } catch (BadLocationException e) {
+ err.println(getString("LogPane.InsertError")); //$NON-NLS-1$
+ } catch (IOException e) {
+ err.println(getString("LogPane.PrintError")); //$NON-NLS-1$
+ }
+
+ }
+
+
+ public void printTimeTaken(Log log) {
+ var time = log.timeTaken();
+ var sb = new StringBuilder();
+ sb.append(getString("LogPane.TimeTaken")); //$NON-NLS-1$
+ sb.append(time[0]).append(getString("LogPane.Seconds")); //$NON-NLS-1$
+ sb.append(time[1]).append(getString("LogPane.Milliseconds")); //$NON-NLS-1$
+ post(sb.toString());
+ }
+
+ @Override
+ public void clear() {
+ try {
+ editor.getDocument().remove(0, editor.getDocument().getLength());
+ } catch (BadLocationException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public JComponent getGUIComponent() {
+ return pane;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return editor.getDocument().getLength() < 1;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/components/buttons/LoaderButton.java b/src/main/java/pulse/ui/components/buttons/LoaderButton.java
index 46c9b43..cad1066 100644
--- a/src/main/java/pulse/ui/components/buttons/LoaderButton.java
+++ b/src/main/java/pulse/ui/components/buttons/LoaderButton.java
@@ -19,7 +19,6 @@
import java.io.File;
import java.io.IOException;
-import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.UIManager;
@@ -27,7 +26,6 @@
import org.apache.commons.math3.exception.OutOfRangeException;
import pulse.input.InterpolationDataset;
-import pulse.ui.Messages;
import pulse.util.ImageUtils;
@SuppressWarnings("serial")
@@ -36,8 +34,8 @@ public class LoaderButton extends JButton {
private InterpolationDataset.StandartType dataType;
private static File dir;
- private final static Color NOT_HIGHLIGHTED = UIManager.getColor("Button.background");
- private final static Color HIGHLIGHTED = ImageUtils.blend(NOT_HIGHLIGHTED, Color.red, 0.75f);
+ private final static Color NOT_HIGHLIGHTED = UIManager.getColor("Button.background");
+ private final static Color HIGHLIGHTED = ImageUtils.blend(NOT_HIGHLIGHTED, Color.red, 0.35f);
public LoaderButton() {
super();
@@ -49,7 +47,7 @@ public LoaderButton(String str) {
init();
}
- public void init() {
+ public final void init() {
InterpolationDataset.addListener(e -> {
if (dataType == e) {
@@ -86,18 +84,17 @@ public void init() {
showMessageDialog(getWindowAncestor((Component) arg0.getSource()), getString("LoaderButton.ReadError"), //$NON-NLS-1$
getString("LoaderButton.IOError"), //$NON-NLS-1$
ERROR_MESSAGE);
- }
- catch(OutOfRangeException ofre) {
+ } catch (OutOfRangeException ofre) {
getDefaultToolkit().beep();
StringBuilder sb = new StringBuilder(getString("TextWrap.0"));
- sb.append(getString("LoaderButton.OFRErrorDescriptor") );
+ sb.append(getString("LoaderButton.OFRErrorDescriptor"));
sb.append(ofre.getMessage());
sb.append(getString("LoaderButton.OFRErrorDescriptor2"));
sb.append(getString("TextWrap.1"));
- showMessageDialog(getWindowAncestor((Component) arg0.getSource()),
- sb.toString(),
+ showMessageDialog(getWindowAncestor((Component) arg0.getSource()),
+ sb.toString(),
getString("LoaderButton.OFRError"), //$NON-NLS-1$
- ERROR_MESSAGE);
+ ERROR_MESSAGE);
}
var size = getDataset(dataType).getData().size();
var label = "";
@@ -113,8 +110,10 @@ public void init() {
default:
throw new IllegalStateException("Unknown data type: " + dataType);
}
+ StringBuilder sb = new StringBuilder("");
+ sb.append(label).append(" data loaded! A total of ").append(size).append(" data points loaded.");
showMessageDialog(getWindowAncestor((Component) arg0.getSource()),
- "" + label + " data loaded! A total of " + size + " data points loaded.",
+ sb.toString(),
"Data loaded", INFORMATION_MESSAGE);
});
}
@@ -124,11 +123,11 @@ public void setDataType(InterpolationDataset.StandartType dataType) {
}
public void highlight(boolean highlighted) {
- setBorder(highlighted ? BorderFactory.createLineBorder(HIGHLIGHTED) : null);
+ setBackground(highlighted ? HIGHLIGHTED : NOT_HIGHLIGHTED);
}
public void highlightIfNeeded() {
highlight(getDataset(dataType) == null);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/components/controllers/AccessibleTableRenderer.java b/src/main/java/pulse/ui/components/controllers/AccessibleTableRenderer.java
index b297d1a..04727c0 100644
--- a/src/main/java/pulse/ui/components/controllers/AccessibleTableRenderer.java
+++ b/src/main/java/pulse/ui/components/controllers/AccessibleTableRenderer.java
@@ -1,6 +1,5 @@
package pulse.ui.components.controllers;
-import static java.awt.Color.RED;
import java.awt.Component;
import java.awt.Font;
@@ -8,7 +7,6 @@
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JTable;
-import javax.swing.UIManager;
import pulse.properties.Flag;
import pulse.properties.NumericProperty;
diff --git a/src/main/java/pulse/ui/components/controllers/InstanceCellEditor.java b/src/main/java/pulse/ui/components/controllers/InstanceCellEditor.java
index 526823f..e9611d7 100644
--- a/src/main/java/pulse/ui/components/controllers/InstanceCellEditor.java
+++ b/src/main/java/pulse/ui/components/controllers/InstanceCellEditor.java
@@ -1,13 +1,11 @@
package pulse.ui.components.controllers;
-import com.alee.utils.swing.PopupMenuAdapter;
import java.awt.Component;
import java.awt.event.ItemEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
-import javax.swing.event.PopupMenuEvent;
import pulse.util.InstanceDescriptor;
@@ -39,17 +37,7 @@ public Component getTableCellEditorComponent(JTable table, Object value, boolean
}
}
});
-
- combobox.addPopupMenuListener(new PopupMenuAdapter() {
-
- @Override
- public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
- fireEditingCanceled();
- }
-
- }
- );
-
+
return combobox;
}
diff --git a/src/main/java/pulse/ui/components/controllers/NumericPropertyRenderer.java b/src/main/java/pulse/ui/components/controllers/NumericPropertyRenderer.java
index e655f9b..5f05afc 100644
--- a/src/main/java/pulse/ui/components/controllers/NumericPropertyRenderer.java
+++ b/src/main/java/pulse/ui/components/controllers/NumericPropertyRenderer.java
@@ -7,10 +7,8 @@
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
-import pulse.math.Segment;
import pulse.properties.NumericProperty;
-import pulse.properties.Property;
import pulse.properties.NumericPropertyFormatter;
@SuppressWarnings("serial")
@@ -29,25 +27,22 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
if (value instanceof NumericProperty) {
var jtf = initTextField((NumericProperty) value, table.isRowSelected(row));
-
if (table.getEditorComponent() != null) {
result = jtf;
} else {
- result = new JLabel(jtf.getText(), JLabel.RIGHT);
- jtf = null;
+ result = (JLabel) super.getTableCellRendererComponent(table,
+ jtf.getText(), isSelected, hasFocus, row, column);
+ ((JLabel) result).setHorizontalAlignment(RIGHT);
}
-
} else {
var superRenderer = (JLabel) super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
superRenderer.setHorizontalAlignment(JLabel.LEFT);
- superRenderer.setBackground(
- isSelected
- ? UIManager.getColor("JFormattedTextField.selectionBackground")
- : UIManager.getColor("JFormattedTextField.background"));
result = superRenderer;
}
+
+ result.setForeground(UIManager.getColor("List.foreground"));
return result;
}
@@ -59,4 +54,4 @@ private static JFormattedTextField initTextField(NumericProperty np, boolean row
return jtf;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/pulse/ui/components/controllers/ProblemCellRenderer.java b/src/main/java/pulse/ui/components/controllers/ProblemCellRenderer.java
index 7c36077..4827624 100644
--- a/src/main/java/pulse/ui/components/controllers/ProblemCellRenderer.java
+++ b/src/main/java/pulse/ui/components/controllers/ProblemCellRenderer.java
@@ -4,20 +4,20 @@
import javax.swing.ImageIcon;
import javax.swing.JTree;
-import javax.swing.UIManager;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
-import com.alee.managers.icon.LazyIcon;
+//import com.alee.managers.icon.LazyIcon;
import pulse.problem.statements.Problem;
import pulse.util.ImageUtils;
+import static pulse.util.ImageUtils.loadIcon;
@SuppressWarnings("serial")
public class ProblemCellRenderer extends DefaultTreeCellRenderer {
- private static ImageIcon defaultIcon = (ImageIcon) ((LazyIcon) UIManager.getIcon("Tree.leafIcon")).getIcon();
-
+ private static ImageIcon defaultIcon = loadIcon("leaf.png", 16);
+
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf,
int row, boolean hasFocus) {
diff --git a/src/main/java/pulse/ui/components/controllers/SearchListRenderer.java b/src/main/java/pulse/ui/components/controllers/SearchListRenderer.java
index e74951a..cfc884c 100644
--- a/src/main/java/pulse/ui/components/controllers/SearchListRenderer.java
+++ b/src/main/java/pulse/ui/components/controllers/SearchListRenderer.java
@@ -2,7 +2,6 @@
import static javax.swing.BorderFactory.createEmptyBorder;
-import java.awt.Color;
import java.awt.Component;
import javax.swing.DefaultListCellRenderer;
@@ -18,8 +17,7 @@ public Component getListCellRendererComponent(JList> list, Object value, int i
var renderer = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
((JComponent) renderer).setBorder(createEmptyBorder(10, 10, 10, 10));
- renderer.setForeground(isSelected ? Color.DARK_GRAY : Color.white);
-
+
return renderer;
}
diff --git a/src/main/java/pulse/ui/components/controllers/TaskTableRenderer.java b/src/main/java/pulse/ui/components/controllers/TaskTableRenderer.java
index 85d3ba6..33ccdcb 100644
--- a/src/main/java/pulse/ui/components/controllers/TaskTableRenderer.java
+++ b/src/main/java/pulse/ui/components/controllers/TaskTableRenderer.java
@@ -3,16 +3,13 @@
import static java.awt.Font.BOLD;
import java.awt.Component;
-import java.awt.Font;
import javax.swing.JLabel;
import javax.swing.JTable;
import pulse.properties.NumericProperty;
-import pulse.properties.Property;
import pulse.tasks.Identifier;
import pulse.tasks.logs.Status;
-import pulse.util.PropertyHolder;
@SuppressWarnings("serial")
public class TaskTableRenderer extends NumericPropertyRenderer {
diff --git a/src/main/java/pulse/ui/components/listeners/LogExportListener.java b/src/main/java/pulse/ui/components/listeners/LogExportListener.java
deleted file mode 100644
index 99a32ae..0000000
--- a/src/main/java/pulse/ui/components/listeners/LogExportListener.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package pulse.ui.components.listeners;
-
-public interface LogExportListener {
-
- public void onLogExportRequest();
-
-}
diff --git a/src/main/java/pulse/ui/components/listeners/LogListener.java b/src/main/java/pulse/ui/components/listeners/LogListener.java
new file mode 100644
index 0000000..5a07f5d
--- /dev/null
+++ b/src/main/java/pulse/ui/components/listeners/LogListener.java
@@ -0,0 +1,8 @@
+package pulse.ui.components.listeners;
+
+public interface LogListener {
+
+ public void onLogExportRequest();
+ public void onLogModeChanged(boolean graphical);
+
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/components/panels/ChartToolbar.java b/src/main/java/pulse/ui/components/panels/ChartToolbar.java
index b4d5e54..dca6e62 100644
--- a/src/main/java/pulse/ui/components/panels/ChartToolbar.java
+++ b/src/main/java/pulse/ui/components/panels/ChartToolbar.java
@@ -38,7 +38,7 @@
public final class ChartToolbar extends JToolBar {
private final static int ICON_SIZE = 16;
- private List listeners;
+ private final List listeners;
private RangeTextFields rtf;
diff --git a/src/main/java/pulse/ui/components/panels/DoubleTablePanel.java b/src/main/java/pulse/ui/components/panels/DoubleTablePanel.java
index 11a5c19..ebb6bf6 100644
--- a/src/main/java/pulse/ui/components/panels/DoubleTablePanel.java
+++ b/src/main/java/pulse/ui/components/panels/DoubleTablePanel.java
@@ -1,18 +1,3 @@
-/*
- * Copyright 2021 kotik.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package pulse.ui.components.panels;
import java.awt.GridBagConstraints;
@@ -87,7 +72,6 @@ public void initComponents(JTable leftTable, String titleLeft, JTable rightTable
var borderLeft = createTitledBorder(titleLeft);
leftScroller.setBorder(borderLeft);
- borderLeft.setTitleColor(java.awt.Color.WHITE);
leftTable.setRowHeight(80);
@@ -102,7 +86,6 @@ public void initComponents(JTable leftTable, String titleLeft, JTable rightTable
var borderRight = createTitledBorder(titleRight);
rightScroller.setBorder(borderRight);
- borderRight.setTitleColor(java.awt.Color.WHITE);
rightTable.setRowHeight(80);
rightScroller.setViewportView(rightTable);
diff --git a/src/main/java/pulse/ui/components/panels/LogToolbar.java b/src/main/java/pulse/ui/components/panels/LogToolbar.java
index a9fd6a1..5db207b 100644
--- a/src/main/java/pulse/ui/components/panels/LogToolbar.java
+++ b/src/main/java/pulse/ui/components/panels/LogToolbar.java
@@ -1,7 +1,5 @@
package pulse.ui.components.panels;
-import static pulse.tasks.logs.Log.isVerbose;
-import static pulse.tasks.logs.Log.setVerbose;
import static pulse.ui.Messages.getString;
import static pulse.util.ImageUtils.loadIcon;
@@ -14,13 +12,15 @@
import javax.swing.JCheckBox;
import javax.swing.JToolBar;
-import pulse.ui.components.listeners.LogExportListener;
+import static pulse.tasks.logs.Log.setGraphicalLog;
+import static pulse.tasks.logs.Log.isGraphicalLog;
+import pulse.ui.components.listeners.LogListener;
@SuppressWarnings("serial")
public class LogToolbar extends JToolBar {
private final static int ICON_SIZE = 16;
- private List listeners;
+ private List listeners;
public LogToolbar() {
super();
@@ -35,24 +35,25 @@ public void initComponents() {
var saveLogBtn = new JButton(loadIcon("save.png", ICON_SIZE, Color.white));
saveLogBtn.setToolTipText("Save");
- var verboseCheckBox = new JCheckBox(getString("LogToolBar.Verbose")); //$NON-NLS-1$
- verboseCheckBox.setSelected(isVerbose());
- verboseCheckBox.setHorizontalAlignment(CENTER);
+ var logmodeCheckbox = new JCheckBox(getString("LogToolBar.Verbose")); //$NON-NLS-1$
+ logmodeCheckbox.setSelected(isGraphicalLog());
+ logmodeCheckbox.setHorizontalAlignment(CENTER);
- verboseCheckBox.addActionListener(event -> setVerbose(verboseCheckBox.isSelected()));
+ logmodeCheckbox.addActionListener(event -> {
+ boolean selected = logmodeCheckbox.isSelected();
+ setGraphicalLog(selected);
+ listeners.stream().forEach(l -> l.onLogModeChanged(selected));
+ });
- saveLogBtn.addActionListener(e -> notifyLog());
+ saveLogBtn.addActionListener(e -> listeners.stream().forEach(l -> l.onLogExportRequest()));
add(saveLogBtn);
- add(verboseCheckBox);
- }
- public void notifyLog() {
- listeners.stream().forEach(l -> l.onLogExportRequest());
+ add(logmodeCheckbox);
}
- public void addLogExportListener(LogExportListener l) {
+ public void addLogListener(LogListener l) {
listeners.add(l);
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/components/panels/ModelToolbar.java b/src/main/java/pulse/ui/components/panels/ModelToolbar.java
index 7c0b550..770734e 100644
--- a/src/main/java/pulse/ui/components/panels/ModelToolbar.java
+++ b/src/main/java/pulse/ui/components/panels/ModelToolbar.java
@@ -18,7 +18,7 @@
@SuppressWarnings("serial")
public class ModelToolbar extends JToolBar {
- private final static int ICON_SIZE = 20;
+ private final static int ICON_SIZE = 16;
public ModelToolbar() {
super();
diff --git a/src/main/java/pulse/ui/components/panels/ProblemToolbar.java b/src/main/java/pulse/ui/components/panels/ProblemToolbar.java
index 92e42ca..e06abd0 100644
--- a/src/main/java/pulse/ui/components/panels/ProblemToolbar.java
+++ b/src/main/java/pulse/ui/components/panels/ProblemToolbar.java
@@ -13,7 +13,6 @@
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
-import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JToolBar;
diff --git a/src/main/java/pulse/ui/frames/LogFrame.java b/src/main/java/pulse/ui/frames/LogFrame.java
index 6410fb7..7eeae66 100644
--- a/src/main/java/pulse/ui/frames/LogFrame.java
+++ b/src/main/java/pulse/ui/frames/LogFrame.java
@@ -6,7 +6,6 @@
import static java.awt.GridBagConstraints.WEST;
import static java.lang.System.err;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static javax.swing.SwingUtilities.getWindowAncestor;
import static pulse.io.export.ExportManager.askToExport;
import static pulse.tasks.listeners.TaskRepositoryEvent.State.TASK_ADDED;
import static pulse.ui.Messages.getString;
@@ -14,22 +13,26 @@
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
-import javax.swing.JFrame;
import javax.swing.JInternalFrame;
-import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
import pulse.tasks.TaskManager;
import pulse.tasks.listeners.LogEntryListener;
import pulse.tasks.logs.Log;
import pulse.tasks.logs.LogEntry;
-import pulse.ui.components.LogPane;
+import pulse.tasks.logs.AbstractLogger;
+import pulse.ui.components.GraphicalLogPane;
+import pulse.ui.components.TextLogPane;
+import pulse.ui.components.listeners.LogListener;
import pulse.ui.components.panels.LogToolbar;
import pulse.ui.components.panels.SystemPanel;
@SuppressWarnings("serial")
public class LogFrame extends JInternalFrame {
- private LogPane logTextPane;
+ private AbstractLogger logger;
+ private final static AbstractLogger graphical = new GraphicalLogPane();
+ private final static AbstractLogger text = new TextLogPane();
public LogFrame() {
super("Log", true, false, true, true);
@@ -39,12 +42,10 @@ public LogFrame() {
}
private void initComponents() {
- logTextPane = new LogPane();
- var logScroller = new JScrollPane();
- logScroller.setViewportView(logTextPane);
+ logger = Log.isGraphicalLog() ? graphical : text;
getContentPane().setLayout(new BorderLayout());
- getContentPane().add(logScroller, CENTER);
+ getContentPane().add(logger.getGUIComponent(), CENTER);
var gridBagConstraints = new GridBagConstraints();
gridBagConstraints.anchor = WEST;
@@ -53,19 +54,31 @@ private void initComponents() {
getContentPane().add(new SystemPanel(), PAGE_END);
var logToolbar = new LogToolbar();
- logToolbar.addLogExportListener(() -> {
- if (logTextPane.getDocument().getLength() > 0) {
- askToExport(logTextPane, (JFrame) getWindowAncestor(this),
- getString("LogToolBar.FileFormatDescriptor"));
+
+ var lel = new LogListener() {
+ @Override
+ public void onLogExportRequest() {
+ if (logger == text) {
+ askToExport(logger, null, getString("LogToolBar.FileFormatDescriptor"));
+ } else {
+ System.out.println("To export the log entries, please switch to text mode first!");
+ }
}
- });
+
+ @Override
+ public void onLogModeChanged(boolean graphical) {
+ SwingUtilities.invokeLater(() -> setGraphicalLogger(graphical));
+ }
+ };
+
+ logToolbar.addLogListener(lel);
getContentPane().add(logToolbar, NORTH);
}
private void scheduleLogEvents() {
var instance = TaskManager.getManagerInstance();
- instance.addSelectionListener(e -> logTextPane.printAll());
+ instance.addSelectionListener(e -> logger.postAll());
instance.addTaskRepositoryListener(event -> {
if (event.getState() != TASK_ADDED) {
@@ -81,13 +94,12 @@ public void onLogFinished(Log log) {
if (instance.getSelectedTask() == task) {
try {
- logTextPane.getUpdateExecutor().awaitTermination(10, MILLISECONDS);
+ logger.getUpdateExecutor().awaitTermination(10, MILLISECONDS);
} catch (InterruptedException e) {
err.println("Log not finished in time");
- e.printStackTrace();
}
- logTextPane.printTimeTaken(log);
+ logger.printTimeTaken(log);
}
}
@@ -95,7 +107,7 @@ public void onLogFinished(Log log) {
@Override
public void onNewEntry(LogEntry e) {
if (instance.getSelectedTask() == task) {
- logTextPane.callUpdate();
+ logger.callUpdate();
}
}
@@ -105,8 +117,20 @@ public void onNewEntry(LogEntry e) {
});
}
- public LogPane getLogTextPane() {
- return logTextPane;
+ public AbstractLogger getLogger() {
+ return logger;
+ }
+
+ private void setGraphicalLogger(boolean graphicalLog) {
+ var old = logger;
+ logger = graphicalLog ? graphical : text;
+
+ if (old != logger) {
+ getContentPane().remove(old.getGUIComponent());
+ getContentPane().add(logger.getGUIComponent(), BorderLayout.CENTER);
+ logger.postAll();
+ }
+
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/pulse/ui/frames/PreviewFrame.java b/src/main/java/pulse/ui/frames/PreviewFrame.java
index 76a249d..508d5a7 100644
--- a/src/main/java/pulse/ui/frames/PreviewFrame.java
+++ b/src/main/java/pulse/ui/frames/PreviewFrame.java
@@ -15,6 +15,7 @@
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
+import static java.awt.Color.WHITE;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.util.ArrayList;
@@ -46,6 +47,7 @@
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import pulse.tasks.processing.ResultFormat;
+import pulse.ui.components.Chart;
@SuppressWarnings("serial")
public class PreviewFrame extends JInternalFrame {
@@ -93,7 +95,6 @@ private void init() {
toolbar.add(selectX);
selectXBox = new JComboBox<>();
- selectXBox.setFont(selectXBox.getFont().deriveFont(11));
toolbar.add(selectXBox);
toolbar.add(new JSeparator());
@@ -102,7 +103,6 @@ private void init() {
toolbar.add(selectY);
selectYBox = new JComboBox<>();
- selectYBox.setFont(selectYBox.getFont().deriveFont(11));
toolbar.add(selectYBox);
var drawSmoothBtn = new JToggleButton();
@@ -229,6 +229,9 @@ private static ChartPanel createEmptyPanel() {
//plot.setRangeGridlinesVisible(false);
//plot.setDomainGridlinesVisible(false);
+ var fore = UIManager.getColor("Label.foreground");
+ plot.setDomainGridlinePaint(fore);
+
plot.getRenderer(1).setSeriesPaint(1, SMOOTH_COLOR);
plot.getRenderer(0).setSeriesPaint(0, RESULT_COLOR);
plot.getRenderer(0).setSeriesShape(0,
@@ -244,6 +247,9 @@ private static ChartPanel createEmptyPanel() {
cp.setMinimumDrawHeight(10);
chart.setBackgroundPaint(UIManager.getColor("Panel.background"));
+ plot.setBackgroundPaint(chart.getBackgroundPaint());
+ Chart.setAxisFontColor(plot.getDomainAxis(), fore);
+ Chart.setAxisFontColor(plot.getRangeAxis(), fore);
return cp;
}
diff --git a/src/main/java/pulse/ui/frames/SearchOptionsFrame.java b/src/main/java/pulse/ui/frames/SearchOptionsFrame.java
index 567c449..f638f4d 100644
--- a/src/main/java/pulse/ui/frames/SearchOptionsFrame.java
+++ b/src/main/java/pulse/ui/frames/SearchOptionsFrame.java
@@ -48,7 +48,6 @@ public class SearchOptionsFrame extends JInternalFrame {
private final JTable rightTable;
private final PathSolversList pathList;
- 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[]{MAXTEMP};
@@ -196,7 +195,6 @@ public PathOptimiser getElementAt(int index) {
}
});
- setFont(FONT);
setSelectionMode(SINGLE_SELECTION);
setCellRenderer(new SearchListRenderer());
diff --git a/src/main/java/pulse/ui/frames/TaskControlFrame.java b/src/main/java/pulse/ui/frames/TaskControlFrame.java
index f04f050..f56d6ed 100644
--- a/src/main/java/pulse/ui/frames/TaskControlFrame.java
+++ b/src/main/java/pulse/ui/frames/TaskControlFrame.java
@@ -55,6 +55,8 @@ public class TaskControlFrame extends JFrame {
private InternalGraphFrame pulseFrame;
private PulseMainMenu mainMenu;
+
+ private final static int ICON_SIZE = 16;
public static TaskControlFrame getInstance() {
return instance;
@@ -157,13 +159,13 @@ public void onRemoveRequest() {
@Override
public void onClearRequest() {
- logFrame.getLogTextPane().clear();
+ logFrame.getLogger().clear();
resultsFrame.getResultTable().clear();
}
@Override
public void onResetRequest() {
- logFrame.getLogTextPane().clear();
+ logFrame.getLogger().clear();
resultsFrame.getResultTable().removeAll();
}
@@ -188,26 +190,26 @@ private void initComponents() {
setJMenuBar(mainMenu);
logFrame = new LogFrame();
- logFrame.setFrameIcon(loadIcon("log.png", 20, Color.white));
+ logFrame.setFrameIcon(loadIcon("log.png", ICON_SIZE, Color.white));
resultsFrame = new ResultFrame();
- resultsFrame.setFrameIcon(loadIcon("result.png", 20, Color.white));
+ resultsFrame.setFrameIcon(loadIcon("result.png", ICON_SIZE, Color.white));
previewFrame = new PreviewFrame();
- previewFrame.setFrameIcon(loadIcon("preview.png", 20, Color.white));
+ previewFrame.setFrameIcon(loadIcon("preview.png", ICON_SIZE, Color.white));
taskManagerFrame = new TaskManagerFrame();
- taskManagerFrame.setFrameIcon(loadIcon("task_manager.png", 20, Color.white));
+ taskManagerFrame.setFrameIcon(loadIcon("task_manager.png", ICON_SIZE, Color.white));
graphFrame = MainGraphFrame.getInstance();
- graphFrame.setFrameIcon(loadIcon("curves.png", 20, Color.white));
+ graphFrame.setFrameIcon(loadIcon("curves.png", ICON_SIZE, Color.white));
problemStatementFrame = new ProblemStatementFrame();
- problemStatementFrame.setFrameIcon(loadIcon("heat_problem.png", 20, Color.white));
+ problemStatementFrame.setFrameIcon(loadIcon("heat_problem.png", ICON_SIZE, Color.white));
modelFrame = new ModelSelectionFrame();
- modelFrame.setFrameIcon(loadIcon("stored.png", 20, Color.white));
+ modelFrame.setFrameIcon(loadIcon("stored.png", ICON_SIZE, Color.white));
searchOptionsFrame = new SearchOptionsFrame();
- searchOptionsFrame.setFrameIcon(loadIcon("optimiser.png", 20, Color.white));
+ searchOptionsFrame.setFrameIcon(loadIcon("optimiser.png", ICON_SIZE, Color.white));
pulseFrame = new InternalGraphFrame("Pulse Shape", new PulseChart("Time (ms)", "Laser Power (a. u.)"));
- pulseFrame.setFrameIcon(loadIcon("pulse.png", 20, Color.white));
+ pulseFrame.setFrameIcon(loadIcon("pulse.png", ICON_SIZE, Color.white));
pulseFrame.setVisible(false);
/*
diff --git a/src/main/resources/NumericProperty.xml b/src/main/resources/NumericProperty.xml
index edf471e..06c47f7 100644
--- a/src/main/resources/NumericProperty.xml
+++ b/src/main/resources/NumericProperty.xml
@@ -1,5 +1,10 @@
+
+
+ minimum="1.0E-4" value="0.01" primitive-type="double" discreet="true" default-search-variable="false">
Time taken:
LogToolBar.FileFormatDescriptor=HTML Log Files
LogToolBar.SaveButton=Save Log
-LogToolBar.Verbose=Verbose log
+LogToolBar.Verbose=Graphical
NumberEditor.EditText=Edit
NumberEditor.IllegalTableEntry=Illegal table entry
NumberEditor.InvalidText=Invalid Text Entered
|