Commit ecdccabe authored by Andrey Filippov's avatar Andrey Filippov

Working on SFE adjustmnent using lens test results

parent fd3a84bd
...@@ -45,6 +45,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -45,6 +45,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
//import FocusingField.MeasuredSample; //import FocusingField.MeasuredSample;
import Jama.Matrix; // Download here: http://math.nist.gov/javanumerics/jama/ import Jama.Matrix; // Download here: http://math.nist.gov/javanumerics/jama/
...@@ -787,14 +788,18 @@ if (MORE_BUTTONS) { ...@@ -787,14 +788,18 @@ if (MORE_BUTTONS) {
panelCurvature.setLayout(new GridLayout(1, 0, 5, 5)); panelCurvature.setLayout(new GridLayout(1, 0, 5, 5));
addButton("Scan Calib LMA", panelCurvature,color_process); addButton("Scan Calib LMA", panelCurvature,color_process);
addButton("Save History", panelCurvature,color_debug); addButton("Save History", panelCurvature,color_debug);
addButton("Restore History",panelCurvature,color_debug); addButton("Restore History",panelCurvature,color_restore);
addButton("Modify LMA", panelCurvature,color_debug); addButton("Modify LMA", panelCurvature,color_configure);
addButton("Load strategies", panelCurvature,color_restore);
addButton("Organize strategies", panelCurvature,color_configure);
addButton("Save strategies", panelCurvature,color_bundle);
addButton("LMA History", panelCurvature,color_process); addButton("LMA History", panelCurvature,color_process);
addButton("List curv pars", panelCurvature,color_debug); addButton("List curv pars", panelCurvature,color_debug);
addButton("List curv data", panelCurvature,color_debug); addButton("List curv data", panelCurvature,color_debug);
addButton("List qualB", panelCurvature,color_report); addButton("List qualB", panelCurvature,color_report);
addButton("List curv", panelCurvature,color_report); addButton("List curv", panelCurvature,color_report);
addButton("Show curv corr", panelCurvature,color_report); addButton("Show curv corr", panelCurvature,color_report);
addButton("Test measurement", panelCurvature,color_process);
add(panelCurvature); add(panelCurvature);
//panelGoniometer //panelGoniometer
...@@ -4386,10 +4391,21 @@ if (MORE_BUTTONS) { ...@@ -4386,10 +4391,21 @@ if (MORE_BUTTONS) {
if (PROPERTIES!=null) FOCUSING_FIELD.getProperties("FOCUSING_FIELD.", PROPERTIES); if (PROPERTIES!=null) FOCUSING_FIELD.getProperties("FOCUSING_FIELD.", PROPERTIES);
System.out.println("Loaded FocusingField"); System.out.println("Loaded FocusingField");
if (!FOCUSING_FIELD.configureDataVector("Configure curvature",true,true)) return; if (!FOCUSING_FIELD.configureDataVector("Configure curvature",true,true)) return;
FOCUSING_FIELD.setDataVector(FOCUSING_FIELD.createDataVector()); /// FOCUSING_FIELD.fieldFitting.initSampleCorrChnParIndex(FOCUSING_FIELD.flattenSampleCoord()); //+
double []focusing_fx=FOCUSING_FIELD.createFXandJacobian(true); /// FOCUSING_FIELD.setDataVector(
double rms= FOCUSING_FIELD.getRMS(focusing_fx,false); /// true, // calibrate mode
System.out.println("rms="+rms); /// FOCUSING_FIELD.createDataVector());
// FOCUSING_FIELD.fieldFitting.initSampleCorrVector( //+
// FOCUSING_FIELD.flattenSampleCoord(), //double [][] sampleCoordinates,
// FOCUSING_FIELD.getSeriesWeights()); //double [][] sampleSeriesWeights);
double [] sv= FOCUSING_FIELD.fieldFitting.createParameterVector(FOCUSING_FIELD.sagittalMaster);
FOCUSING_FIELD.setDataVector(
true, // calibrate mode
FOCUSING_FIELD.createDataVector());
double [] focusing_fx= FOCUSING_FIELD.createFXandJacobian(sv, false);
double rms= FOCUSING_FIELD.calcErrorDiffY(focusing_fx, false);
double rms_pure= FOCUSING_FIELD.calcErrorDiffY(focusing_fx, true);
System.out.println("rms="+rms+", rms_pure="+rms_pure);
return; return;
} }
/* ======================================================================== */ /* ======================================================================== */
...@@ -4398,15 +4414,49 @@ if (MORE_BUTTONS) { ...@@ -4398,15 +4414,49 @@ if (MORE_BUTTONS) {
if (FOCUSING_FIELD==null) return; if (FOCUSING_FIELD==null) return;
FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL); FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL);
if (!FOCUSING_FIELD.configureDataVector("Re-configure curvature parameters",false,true)) return; if (!FOCUSING_FIELD.configureDataVector("Re-configure curvature parameters",false,true)) return;
FOCUSING_FIELD.setDataVector(FOCUSING_FIELD.createDataVector()); FOCUSING_FIELD.setDataVector(
true, // calibrate mode
FOCUSING_FIELD.createDataVector());
return;
}
/* ======================================================================== */
if (label.equals("Load strategies")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (FOCUSING_FIELD==null) return;
FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL);
FOCUSING_FIELD.fieldFitting.fieldStrategies.loadStrategies(null,PROCESS_PARAMETERS.kernelsDirectory);
return;
}
/* ======================================================================== */
if (label.equals("Save strategies")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (FOCUSING_FIELD==null) return;
FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL);
FOCUSING_FIELD.fieldFitting.fieldStrategies.saveStrategies(null,PROCESS_PARAMETERS.kernelsDirectory);
return; return;
} }
/* ======================================================================== */
if (label.equals("Organize strategies")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (FOCUSING_FIELD==null) return;
FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL);
int resp=0;
while (resp==0){
resp=FOCUSING_FIELD.organizeStrategies("Organize LMA strategies");
}
return;
}
///organizeStrategies(String title)
/* ======================================================================== */ /* ======================================================================== */
if (label.equals("LMA History")) { if (label.equals("LMA History")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL; DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (FOCUSING_FIELD==null) return; if (FOCUSING_FIELD==null) return;
FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL); FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL);
FOCUSING_FIELD.LevenbergMarquardt(true, DEBUG_LEVEL); //boolean openDialog, int debugLevel){ FOCUSING_FIELD.LevenbergMarquardt(
null, // measurement
true, // open dialog
false, // filterZ
DEBUG_LEVEL); //boolean openDialog, int debugLevel){
return; return;
} }
/* ======================================================================== */ /* ======================================================================== */
...@@ -4450,6 +4500,14 @@ if (MORE_BUTTONS) { ...@@ -4450,6 +4500,14 @@ if (MORE_BUTTONS) {
FOCUSING_FIELD.showCurvCorr(); // to screen FOCUSING_FIELD.showCurvCorr(); // to screen
return; return;
} }
/* ======================================================================== */
if (label.equals("Test measurement")) {
DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
if (FOCUSING_FIELD==null) return;
FOCUSING_FIELD.setDebugLevel(DEBUG_LEVEL);
FOCUSING_FIELD.testMeasurement();
return;
}
// //
/* ======================================================================== */ /* ======================================================================== */
if (label.equals("Show PSF")) { if (label.equals("Show PSF")) {
......
...@@ -30,8 +30,13 @@ import ij.text.TextWindow; ...@@ -30,8 +30,13 @@ import ij.text.TextWindow;
import java.awt.Point; import java.awt.Point;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
...@@ -42,6 +47,12 @@ import org.apache.commons.configuration.ConfigurationException; ...@@ -42,6 +47,12 @@ import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration; import org.apache.commons.configuration.XMLConfiguration;
//import Distortions.LMAArrays; // may still reuse? //import Distortions.LMAArrays; // may still reuse?
import Jama.LUDecomposition; import Jama.LUDecomposition;
import Jama.Matrix; import Jama.Matrix;
...@@ -68,6 +79,9 @@ public class FocusingField { ...@@ -68,6 +79,9 @@ public class FocusingField {
boolean filterInputConcaveRemoveFew; boolean filterInputConcaveRemoveFew;
int filterInputConcaveMinSeries; int filterInputConcaveMinSeries;
double filterInputConcaveScale; double filterInputConcaveScale;
boolean filterZ; // (adjustment mode)filter samples by Z
int minLeftSamples; // minimal number of samples (channel/dir/location) for adjustment
// when false - tangential is master // when false - tangential is master
double [] minMeas; // pixels double [] minMeas; // pixels
double [] maxMeas; // pixels double [] maxMeas; // pixels
...@@ -107,12 +121,17 @@ public class FocusingField { ...@@ -107,12 +121,17 @@ public class FocusingField {
private int numIterations; // maximal number of iterations private int numIterations; // maximal number of iterations
private double maxLambda; // max lambda to fail private double maxLambda; // max lambda to fail
private double lambda; // copied from series private double lambda; // copied from series
private String strategyComment;
private boolean lastInSeries;
private int currentStrategyStep; // -1 do not read from strategies
private boolean stopEachStep; // open dialog after each fitting step private boolean stopEachStep; // open dialog after each fitting step
private boolean stopEachSeries; // stop after each series
private boolean stopOnFailure; // open dialog when fitting series failed private boolean stopOnFailure; // open dialog when fitting series failed
private boolean showParams; // show modified parameters private boolean showParams; // show modified parameters
private boolean showDisabledParams; private boolean showDisabledParams;
private boolean showCorrectionParams; private boolean showCorrectionParams;
private boolean keepCorrectionParameters; private boolean keepCorrectionParameters;
private boolean resetCenter; // use distortion center
private boolean saveSeries; // just for the dialog private boolean saveSeries; // just for the dialog
private boolean showMotors; private boolean showMotors;
private boolean [] showMeasCalc; private boolean [] showMeasCalc;
...@@ -151,6 +170,9 @@ public class FocusingField { ...@@ -151,6 +170,9 @@ public class FocusingField {
public ArrayList<FocusingFieldMeasurement> measurements; public ArrayList<FocusingFieldMeasurement> measurements;
double [] weightReference=null; // calculated per-channel (6) array of maximal PSF FWHM after applying min/max correction double [] weightReference=null; // calculated per-channel (6) array of maximal PSF FWHM after applying min/max correction
MeasuredSample [] dataVector; MeasuredSample [] dataVector;
double [][][] zRanges; // min/max "reliable" z for each channel/sample - will be used during adjustment
boolean [] prevEnable; // used in adjustment mode to save previous result of filterByZRanges()
// boolean changedEnable; // used in adjustment mode to signal if new result of filterByZRanges() differes from the previous one
double [] dataValues; double [] dataValues;
double [] dataWeights; double [] dataWeights;
// int [][][] dataIndex=null; // [measurement][channel][sample] - index in dataValues (and dataWeights) or -1 // int [][][] dataIndex=null; // [measurement][channel][sample] - index in dataValues (and dataWeights) or -1
...@@ -162,7 +184,8 @@ public class FocusingField { ...@@ -162,7 +184,8 @@ public class FocusingField {
private LMAArrays lMAArrays=null; private LMAArrays lMAArrays=null;
private LMAArrays savedLMAArrays=null; private LMAArrays savedLMAArrays=null;
private double [] currentfX=null; // array of "f(x)" - simulated data for all images, combining pixel-X and pixel-Y (odd/even) // temporarily changing visibility of currentfX
double [] currentfX=null; // array of "f(x)" - simulated data for all images, combining pixel-X and pixel-Y (odd/even)
private double [] nextfX=null; // array of "f(x)" - simulated data for all images, combining pixel-X and pixel-Y (odd/even) private double [] nextfX=null; // array of "f(x)" - simulated data for all images, combining pixel-X and pixel-Y (odd/even)
private double currentRMS=-1.0; // calculated RMS for the currentVector->currentfX private double currentRMS=-1.0; // calculated RMS for the currentVector->currentfX
private double currentRMSPure=-1.0; // calculated RMS for the currentVector->currentfX private double currentRMSPure=-1.0; // calculated RMS for the currentVector->currentfX
...@@ -174,6 +197,9 @@ public class FocusingField { ...@@ -174,6 +197,9 @@ public class FocusingField {
public void setDefaults(){ public void setDefaults(){
zRanges=null;
prevEnable=null;
// changedEnable=true;
z0_estimates=null; z0_estimates=null;
sagittalMaster=false; // center data is the same, when true sagittal fitting only may change r=0 coefficients, sagittalMaster=false; // center data is the same, when true sagittal fitting only may change r=0 coefficients,
parallelOnly = true; // only process measurements for parallel moves parallelOnly = true; // only process measurements for parallel moves
...@@ -188,6 +214,9 @@ public class FocusingField { ...@@ -188,6 +214,9 @@ public class FocusingField {
filterInputConcaveRemoveFew=true; filterInputConcaveRemoveFew=true;
filterInputConcaveMinSeries=5; filterInputConcaveMinSeries=5;
filterInputConcaveScale=0.9; filterInputConcaveScale=0.9;
filterZ=true; // (adjustment mode)filter samples by Z
minLeftSamples=10; // minimal number of samples (channel/dir/location) for adjustment
// when false - tangential is master // when false - tangential is master
double [] minMeasDflt= {0.5,0.5,0.5,0.5,0.5,0.5}; // pixels double [] minMeasDflt= {0.5,0.5,0.5,0.5,0.5,0.5}; // pixels
minMeas= minMeasDflt; // pixels minMeas= minMeasDflt; // pixels
...@@ -229,14 +258,20 @@ public class FocusingField { ...@@ -229,14 +258,20 @@ public class FocusingField {
thresholdFinish=0.001; // (copied from series) stop iterations if 2 last steps had less improvement (but not worsening ) thresholdFinish=0.001; // (copied from series) stop iterations if 2 last steps had less improvement (but not worsening )
numIterations= 100; // maximal number of iterations numIterations= 100; // maximal number of iterations
maxLambda= 100.0; // max lambda to fail maxLambda= 100.0; // max lambda to fail
lambda=0.001; // copied from series lambda=0.001; // copied from series
stopEachStep= true; // open dialog after each fitting step stopEachStep= true; // open dialog after each fitting step
stopEachSeries= false;
stopOnFailure= true; // open dialog when fitting series failed stopOnFailure= true; // open dialog when fitting series failed
strategyComment="";
lastInSeries=true;
currentStrategyStep=-1; // -1 do not read from strategies
showParams= false; // show modified parameters showParams= false; // show modified parameters
showDisabledParams = false; showDisabledParams = false;
showCorrectionParams = false; showCorrectionParams = false;
keepCorrectionParameters = true; keepCorrectionParameters = true;
resetCenter=false;
saveSeries=false; // just for the dialog saveSeries=false; // just for the dialog
showMotors = true; showMotors = true;
...@@ -283,21 +318,19 @@ public class FocusingField { ...@@ -283,21 +318,19 @@ public class FocusingField {
properties.setProperty(prefix+"filterInputFirstLast",filterInputFirstLast+""); properties.setProperty(prefix+"filterInputFirstLast",filterInputFirstLast+"");
properties.setProperty(prefix+"filterInputTooFar",filterInputTooFar+""); properties.setProperty(prefix+"filterInputTooFar",filterInputTooFar+"");
properties.setProperty(prefix+"filterInputFarRatio",filterInputFarRatio+""); properties.setProperty(prefix+"filterInputFarRatio",filterInputFarRatio+"");
properties.setProperty(prefix+"filterInputConcave",filterInputConcave+""); properties.setProperty(prefix+"filterInputConcave",filterInputConcave+"");
properties.setProperty(prefix+"filterInputConcaveSigma",filterInputConcaveSigma+""); properties.setProperty(prefix+"filterInputConcaveSigma",filterInputConcaveSigma+"");
properties.setProperty(prefix+"filterInputConcaveRemoveFew",filterInputConcaveRemoveFew+""); properties.setProperty(prefix+"filterInputConcaveRemoveFew",filterInputConcaveRemoveFew+"");
properties.setProperty(prefix+"filterInputConcaveMinSeries",filterInputConcaveMinSeries+""); properties.setProperty(prefix+"filterInputConcaveMinSeries",filterInputConcaveMinSeries+"");
properties.setProperty(prefix+"filterInputConcaveScale",filterInputConcaveScale+""); properties.setProperty(prefix+"filterInputConcaveScale",filterInputConcaveScale+"");
properties.setProperty(prefix+"filterZ",filterZ+"");
properties.setProperty(prefix+"minLeftSamples",minLeftSamples+"");
for (int chn=0; chn<minMeas.length; chn++) properties.setProperty(prefix+"minMeas_"+chn,minMeas[chn]+""); for (int chn=0; chn<minMeas.length; chn++) properties.setProperty(prefix+"minMeas_"+chn,minMeas[chn]+"");
for (int chn=0; chn<maxMeas.length; chn++) properties.setProperty(prefix+"maxMeas_"+chn,maxMeas[chn]+""); for (int chn=0; chn<maxMeas.length; chn++) properties.setProperty(prefix+"maxMeas_"+chn,maxMeas[chn]+"");
for (int chn=0; chn<thresholdMax.length; chn++) properties.setProperty(prefix+"thresholdMax_"+chn,thresholdMax[chn]+""); for (int chn=0; chn<thresholdMax.length; chn++) properties.setProperty(prefix+"thresholdMax_"+chn,thresholdMax[chn]+"");
properties.setProperty(prefix+"useMinMeas",useMinMeas+""); properties.setProperty(prefix+"useMinMeas",useMinMeas+"");
properties.setProperty(prefix+"useMaxMeas",useMaxMeas+""); properties.setProperty(prefix+"useMaxMeas",useMaxMeas+"");
properties.setProperty(prefix+"useThresholdMax",useThresholdMax+""); properties.setProperty(prefix+"useThresholdMax",useThresholdMax+"");
properties.setProperty(prefix+"weightMode",weightMode+""); properties.setProperty(prefix+"weightMode",weightMode+"");
properties.setProperty(prefix+"weightRadius",weightRadius+""); properties.setProperty(prefix+"weightRadius",weightRadius+"");
properties.setProperty(prefix+"k_red",k_red+""); properties.setProperty(prefix+"k_red",k_red+"");
...@@ -321,6 +354,17 @@ public class FocusingField { ...@@ -321,6 +354,17 @@ public class FocusingField {
properties.setProperty(prefix+"rslt_mtf50_mode",rslt_mtf50_mode+""); properties.setProperty(prefix+"rslt_mtf50_mode",rslt_mtf50_mode+"");
properties.setProperty(prefix+"rslt_solve",rslt_solve+""); properties.setProperty(prefix+"rslt_solve",rslt_solve+"");
for (int chn=0; chn<rslt_show_chn.length; chn++) properties.setProperty(prefix+"rslt_show_chn_"+chn,rslt_show_chn[chn]+""); for (int chn=0; chn<rslt_show_chn.length; chn++) properties.setProperty(prefix+"rslt_show_chn_"+chn,rslt_show_chn[chn]+"");
// always re-calculate here?
zRanges=calcZRanges(dataWeightsToBoolean());
if (zRanges!=null){
properties.setProperty(prefix+"zRanges_length",zRanges.length+"");
for (int chn=0;chn<zRanges.length;chn++) if (zRanges[chn]!=null) {
properties.setProperty(prefix+"zRanges_"+chn+"_length",zRanges[chn].length+"");
for (int sample=0;sample<zRanges[chn].length;sample++) if (zRanges[chn][sample]!=null) {
properties.setProperty(prefix+"zRanges_"+chn+"_"+sample,zRanges[chn][sample][0]+","+zRanges[chn][sample][1]);
}
}
}
} }
public void getProperties(String prefix,Properties properties){ public void getProperties(String prefix,Properties properties){
...@@ -363,7 +407,6 @@ public class FocusingField { ...@@ -363,7 +407,6 @@ public class FocusingField {
if (properties.getProperty(prefix+"filterInputConcaveSigma")!=null) if (properties.getProperty(prefix+"filterInputConcaveSigma")!=null)
filterInputConcaveSigma=Double.parseDouble(properties.getProperty(prefix+"filterInputConcaveSigma")); filterInputConcaveSigma=Double.parseDouble(properties.getProperty(prefix+"filterInputConcaveSigma"));
if (properties.getProperty(prefix+"filterInputConcaveRemoveFew")!=null) if (properties.getProperty(prefix+"filterInputConcaveRemoveFew")!=null)
filterInputConcaveRemoveFew=Boolean.parseBoolean(properties.getProperty(prefix+"filterInputConcaveRemoveFew")); filterInputConcaveRemoveFew=Boolean.parseBoolean(properties.getProperty(prefix+"filterInputConcaveRemoveFew"));
if (properties.getProperty(prefix+"filterInputConcaveMinSeries")!=null) if (properties.getProperty(prefix+"filterInputConcaveMinSeries")!=null)
...@@ -371,6 +414,11 @@ public class FocusingField { ...@@ -371,6 +414,11 @@ public class FocusingField {
if (properties.getProperty(prefix+"filterInputConcaveScale")!=null) if (properties.getProperty(prefix+"filterInputConcaveScale")!=null)
filterInputConcaveScale=Double.parseDouble(properties.getProperty(prefix+"filterInputConcaveScale")); filterInputConcaveScale=Double.parseDouble(properties.getProperty(prefix+"filterInputConcaveScale"));
if (properties.getProperty(prefix+"filterZ")!=null)
filterZ=Boolean.parseBoolean(properties.getProperty(prefix+"filterZ"));
if (properties.getProperty(prefix+"minLeftSamples")!=null)
minLeftSamples=Integer.parseInt(properties.getProperty(prefix+"minLeftSamples"));
for (int chn=0; chn<minMeas.length; chn++) if (properties.getProperty(prefix+"minMeas_"+chn)!=null) for (int chn=0; chn<minMeas.length; chn++) if (properties.getProperty(prefix+"minMeas_"+chn)!=null)
minMeas[chn]=Double.parseDouble(properties.getProperty(prefix+"minMeas_"+chn)); minMeas[chn]=Double.parseDouble(properties.getProperty(prefix+"minMeas_"+chn));
for (int chn=0; chn<maxMeas.length; chn++) if (properties.getProperty(prefix+"maxMeas_"+chn)!=null) for (int chn=0; chn<maxMeas.length; chn++) if (properties.getProperty(prefix+"maxMeas_"+chn)!=null)
...@@ -429,6 +477,26 @@ public class FocusingField { ...@@ -429,6 +477,26 @@ public class FocusingField {
rslt_solve=Boolean.parseBoolean(properties.getProperty(prefix+"rslt_solve")); rslt_solve=Boolean.parseBoolean(properties.getProperty(prefix+"rslt_solve"));
for (int chn=0; chn<rslt_show_chn.length; chn++) if (properties.getProperty(prefix+"rslt_show_chn_"+chn)!=null) for (int chn=0; chn<rslt_show_chn.length; chn++) if (properties.getProperty(prefix+"rslt_show_chn_"+chn)!=null)
rslt_show_chn[chn]=Boolean.parseBoolean(properties.getProperty(prefix+"rslt_show_chn_"+chn)); rslt_show_chn[chn]=Boolean.parseBoolean(properties.getProperty(prefix+"rslt_show_chn_"+chn));
zRanges=null;
if (properties.getProperty(prefix+"zRanges_length")!=null){
zRanges=new double [Integer.parseInt(properties.getProperty(prefix+"zRanges_length"))][][];
for (int chn=0;chn<zRanges.length;chn++) {
zRanges[chn]=null;
if (properties.getProperty(prefix+"zRanges_"+chn+"_length")!=null){
zRanges[chn]=new double [Integer.parseInt(properties.getProperty(prefix+"zRanges_"+chn+"_length"))][];
for (int sample=0;sample<zRanges[chn].length;sample++) {
zRanges[chn][sample]=null;
String s=properties.getProperty(prefix+"zRanges_"+chn+"_"+sample);
if (s!=null){
zRanges[chn][sample]=new double[2];
String [] ss=s.split(",");
zRanges[chn][sample][0]=Double.parseDouble(ss[0]);
zRanges[chn][sample][1]=Double.parseDouble(ss[1]);
}
}
}
}
}
} }
public void setDebugLevel(int debugLevel){ public void setDebugLevel(int debugLevel){
this.debugLevel=debugLevel; this.debugLevel=debugLevel;
...@@ -666,6 +734,67 @@ public double [][] getSeriesWeights(){ ...@@ -666,6 +734,67 @@ public double [][] getSeriesWeights(){
return seriesWeights; return seriesWeights;
} }
private double [][][] calcZRanges(
boolean [] enable){
double [][][] zRanges=new double[getNumChannels()][getNumSamples()][];
for (int chn=0;chn<zRanges.length;chn++) for (int sample=0;sample<zRanges[chn].length;sample++) zRanges[chn][sample]=null;
double [][] sCoord= flattenSampleCoord();
for (int index=0;index<dataVector.length;index++) if ((index>=enable.length) ||enable[index]){
int chn=dataVector[index].channel;
int sample=dataVector[index].sampleIndex;
double z= fieldFitting.getMotorsZ(
dataVector[index].motors, // 3 motor coordinates
sCoord[sample][0], // pixel x
sCoord[sample][1]); // pixel y
if (zRanges[chn][sample]==null){
zRanges[chn][sample]=new double[2];
zRanges[chn][sample][0]=z;
zRanges[chn][sample][1]=z;
} else {
if (z<zRanges[chn][sample][0]) zRanges[chn][sample][0]=z;
if (z>zRanges[chn][sample][1]) zRanges[chn][sample][1]=z;
}
}
if (debugLevel>0) System.out.println("calcZRanges()");
return zRanges;
}
private boolean [] filterByZRanges (
double [][][] zRanges,
boolean [] enable_in){
boolean [] enable_out=enable_in.clone();
double [][] sCoord= flattenSampleCoord();
int numFiltered=0;
int numLeft=0;
if (zRanges!=null) {
for (int index=0;index<dataVector.length;index++) if ((index>=enable_in.length) || enable_in[index]){
int chn=dataVector[index].channel;
int sample=dataVector[index].sampleIndex;
double z= fieldFitting.getMotorsZ(
dataVector[index].motors, // 3 motor coordinates
sCoord[sample][0], // pixel x
sCoord[sample][1]); // pixel y
if ((zRanges[chn]!=null) && (zRanges[chn][sample]!=null)){
if ((z<zRanges[chn][sample][0]) || (z>zRanges[chn][sample][1])) {
enable_out[index]=false;
numFiltered++;
} else {
numLeft++;
}
}
}
}
if (debugLevel>1) System.out.println("filterByZRanges(): Filtered "+numFiltered+" samples, left "+numLeft+" samples");
return enable_out;
}
private int getNumEnabledSamples(
boolean [] enable){
int num_en=0;
for (int index=0;index<dataVector.length;index++) if ((index>=enable.length) || enable[index]) num_en++;
return num_en;
}
private boolean [] filterConcave( private boolean [] filterConcave(
double sigma, double sigma,
...@@ -1029,10 +1158,12 @@ private int [] getParallelDiff(MeasuredSample [] vector){ ...@@ -1029,10 +1158,12 @@ private int [] getParallelDiff(MeasuredSample [] vector){
// includes deselected channels // includes deselected channels
public void setDataVector(MeasuredSample [] vector){ // remove unused channels if any. vector is already corrected from input data, FWHM psf public void setDataVector(
boolean calibrateMode,
MeasuredSample [] vector){ // remove unused channels if any. vector is already corrected from input data, FWHM psf
if (debugLevel>1) System.out.println("+++++ (Re)calculating sample weights +++++"); if (debugLevel>1) System.out.println("+++++ (Re)calculating sample weights +++++");
int [] diffs=null; int [] diffs=null;
if (parallelOnly) diffs=getParallelDiff(vector); if (calibrateMode && parallelOnly) diffs=getParallelDiff(vector);
boolean [] chanSel=fieldFitting.getSelectedChannels(); boolean [] chanSel=fieldFitting.getSelectedChannels();
int numSamples=0; int numSamples=0;
for (int i=0;i<vector.length;i++) if (chanSel[vector[i].channel]){ for (int i=0;i<vector.length;i++) if (chanSel[vector[i].channel]){
...@@ -1052,36 +1183,21 @@ public void setDataVector(MeasuredSample [] vector){ // remove unused channels i ...@@ -1052,36 +1183,21 @@ public void setDataVector(MeasuredSample [] vector){ // remove unused channels i
int corrLength=fieldFitting.getNumberOfCorrParameters(); int corrLength=fieldFitting.getNumberOfCorrParameters();
dataValues = new double [dataVector.length+corrLength]; dataValues = new double [dataVector.length+corrLength];
dataWeights = new double [dataVector.length+corrLength]; dataWeights = new double [dataVector.length+corrLength];
// sumWeights=0.0;
// int mode=weightMode;
double kw= (weightRadius>0.0)?(-0.5*getPixelMM()*getPixelMM()/(weightRadius*weightRadius)):0; double kw= (weightRadius>0.0)?(-0.5*getPixelMM()*getPixelMM()/(weightRadius*weightRadius)):0;
//weightRadius
// if (weightReference==null) mode=0;
for (int i=0;i<dataVector.length;i++){ for (int i=0;i<dataVector.length;i++){
MeasuredSample ms=dataVector[i]; MeasuredSample ms=dataVector[i];
dataValues[i]=ms.value; dataValues[i]=ms.value;
dataWeights[i]=1.0/Math.pow(ms.value,weightMode); dataWeights[i]=1.0/Math.pow(ms.value,weightMode);
/*
double diff=weightReference[ms.channel]-ms.value;
if (diff<0.0) diff=0;
switch (mode){
case 0: dataWeights[i]=1.0; break;
case 1: dataWeights[i]=diff; break;
case 2: dataWeights[i]=diff*diff; break;
default: dataWeights[i]=1.0;
}
*/
if (weightRadius>0.0){ if (weightRadius>0.0){
double r2=(ms.px-currentPX0)*(ms.px-currentPX0)+(ms.py-currentPY0)*(ms.py-currentPY0); double r2=(ms.px-currentPX0)*(ms.px-currentPX0)+(ms.py-currentPY0)*(ms.py-currentPY0);
dataWeights[i]*=Math.exp(kw*r2); dataWeights[i]*=Math.exp(kw*r2);
} }
// sumWeights+=dataWeights[i];
} }
for (int i=0;i<corrLength;i++){ for (int i=0;i<corrLength;i++){
dataValues[i+dataVector.length]=0.0; // correction target is always 0 dataValues[i+dataVector.length]=0.0; // correction target is always 0
dataWeights[i+dataVector.length]=1.0; // improve? dataWeights[i+dataVector.length]=1.0; // improve?
} }
if (filterInput){ if (calibrateMode && filterInput){
boolean [] en=dataWeightsToBoolean(); boolean [] en=dataWeightsToBoolean();
en= filterCrazyInput( en= filterCrazyInput(
en, // [meas][cjn][sample] (or null) // can be shorter or longer than dataVector en, // [meas][cjn][sample] (or null) // can be shorter or longer than dataVector
...@@ -1091,7 +1207,7 @@ public void setDataVector(MeasuredSample [] vector){ // remove unused channels i ...@@ -1091,7 +1207,7 @@ public void setDataVector(MeasuredSample [] vector){ // remove unused channels i
); );
maskDataWeights(en); maskDataWeights(en);
} }
if (filterInputTooFar){ if (calibrateMode && filterInputTooFar){
boolean [] en=dataWeightsToBoolean(); boolean [] en=dataWeightsToBoolean();
en= filterTooFar( en= filterTooFar(
filterInputFarRatio, filterInputFarRatio,
...@@ -1099,7 +1215,7 @@ public void setDataVector(MeasuredSample [] vector){ // remove unused channels i ...@@ -1099,7 +1215,7 @@ public void setDataVector(MeasuredSample [] vector){ // remove unused channels i
maskDataWeights(en); maskDataWeights(en);
} }
if (filterInputConcave){ if (calibrateMode && filterInputConcave){
boolean [] en=dataWeightsToBoolean(); boolean [] en=dataWeightsToBoolean();
en= filterConcave( en= filterConcave(
filterInputConcaveSigma, filterInputConcaveSigma,
...@@ -1126,16 +1242,17 @@ public void commitParameterVector(double [] vector){ ...@@ -1126,16 +1242,17 @@ public void commitParameterVector(double [] vector){
if (centerSelect[0] ||centerSelect[1]){ // do not do that if XC, YC are not modified if (centerSelect[0] ||centerSelect[1]){ // do not do that if XC, YC are not modified
// recalculate data vector // recalculate data vector
double [] pXY=fieldFitting.getCenterXY(); double [] pXY=fieldFitting.getCenterXY();
if (debugLevel>0) System.out.println("Updated currentPX0="+pXY[0]+"("+currentPX0+")"+", currentPY0="+pXY[1]+"("+currentPY0+")");
currentPX0=pXY[0]; currentPX0=pXY[0];
currentPY0=pXY[1]; currentPY0=pXY[1];
if (debugLevel>0) System.out.println("Updated currentPX0="+currentPX0+", currentPY0="+currentPY0);
if (correct_measurement_ST && updateWeightWhileFitting) { if (correct_measurement_ST && updateWeightWhileFitting) {
setDataVector(createDataVector( setDataVector(
true,
createDataVector(
false, // boolean updateSelection, false, // boolean updateSelection,
pXY[0], //double centerPX, pXY[0], //double centerPX,
pXY[1])); //double centerPY pXY[1])); //double centerPY
} }
} }
} }
...@@ -1310,6 +1427,22 @@ public double getRMS(double [] fx, boolean pure){ ...@@ -1310,6 +1427,22 @@ public double getRMS(double [] fx, boolean pure){
return Math.sqrt(sum); return Math.sqrt(sum);
} }
public MeasuredSample [] createDataVector(FocusingFieldMeasurement measurement){
ArrayList<FocusingFieldMeasurement> singleMeasurement=new ArrayList<FocusingFieldMeasurement>();
singleMeasurement.add(measurement);
return createDataVector(
singleMeasurement,
false, // calibrate
true, // update selection
currentPX0, // ignored
currentPY0, // ignored
(this.useMinMeas?this.minMeas:null), // pixels
(this.useMaxMeas?this.maxMeas:null), // pixels
(this.useThresholdMax?this.thresholdMax:null)); // pixels
}
public MeasuredSample [] createDataVector(){ public MeasuredSample [] createDataVector(){
return createDataVector( return createDataVector(
true, // boolean updateSelection, true, // boolean updateSelection,
...@@ -1322,6 +1455,8 @@ public MeasuredSample [] createDataVector( ...@@ -1322,6 +1455,8 @@ public MeasuredSample [] createDataVector(
double centerPY double centerPY
){ // use this data ){ // use this data
return createDataVector( return createDataVector(
measurements,
true, // calibrate
updateSelection, updateSelection,
centerPX, centerPX,
centerPY, centerPY,
...@@ -1379,6 +1514,8 @@ d_cs/dy0= delta_x*(2*delta_y^2-r2)/r2^2 ...@@ -1379,6 +1514,8 @@ d_cs/dy0= delta_x*(2*delta_y^2-r2)/r2^2
*/ */
public MeasuredSample [] createDataVector( public MeasuredSample [] createDataVector(
ArrayList<FocusingFieldMeasurement> measurements,
boolean calibrate, // false - adjust, should have updateSelection==true and a single-element measurements list
boolean updateSelection, boolean updateSelection,
double centerPX, double centerPX,
double centerPY, double centerPY,
...@@ -1386,8 +1523,10 @@ public MeasuredSample [] createDataVector( ...@@ -1386,8 +1523,10 @@ public MeasuredSample [] createDataVector(
double [] maxMeas, // pixels double [] maxMeas, // pixels
double [] thresholdMax){ // pixels double [] thresholdMax){ // pixels
debugDerivatives=debugLevel==3; debugDerivatives=debugLevel==3;
if (calibrate) {
currentPX0=centerPX; currentPX0=centerPX;
currentPY0=centerPY; currentPY0=centerPY;
}
final int numColors=3; final int numColors=3;
final int numDirs=2; final int numDirs=2;
if (sampleMask== null) updateSelection=true; if (sampleMask== null) updateSelection=true;
...@@ -1401,7 +1540,7 @@ public MeasuredSample [] createDataVector( ...@@ -1401,7 +1540,7 @@ public MeasuredSample [] createDataVector(
for (int d=0;d<numDirs;d++) sampleMask[n][i][j][c][d]=false; for (int d=0;d<numDirs;d++) sampleMask[n][i][j][c][d]=false;
} }
/* /*
d_c2/d_x0= 2*delta_x*(delta_x^2 - r2)/r2^2 d_c2/d_x0= 2*delta_x*(delta_x^2 - r2)/r2^2
d_c2/d_y0= 2*delta_y*delta_x^2/r2^2 d_c2/d_y0= 2*delta_y*delta_x^2/r2^2
...@@ -1410,7 +1549,7 @@ d_s2/d_x0= 2*delta_x*delta_y^2/r2^2 ...@@ -1410,7 +1549,7 @@ d_s2/d_x0= 2*delta_x*delta_y^2/r2^2
2*d_cs/dx0= 2*delta_y*(2*delta_x^2-r2)/r2^2 2*d_cs/dx0= 2*delta_y*(2*delta_x^2-r2)/r2^2
2*d_cs/dy0= 2*delta_x*(2*delta_y^2-r2)/r2^2 2*d_cs/dy0= 2*delta_x*(2*delta_y^2-r2)/r2^2
*/ */
double [][][] cosSin2Tab=new double[sampleCoord.length][sampleCoord[0].length][3]; double [][][] cosSin2Tab=new double[sampleCoord.length][sampleCoord[0].length][3];
double [][][] debugCosSin2Tab_dx=null; double [][][] debugCosSin2Tab_dx=null;
double [][][] debugCosSin2Tab_dy=null; double [][][] debugCosSin2Tab_dy=null;
...@@ -1636,8 +1775,8 @@ d_s2/d_x0= 2*delta_x*delta_y^2/r2^2 ...@@ -1636,8 +1775,8 @@ d_s2/d_x0= 2*delta_x*delta_y^2/r2^2
} }
double f=value; double f=value;
value = 1.0/Math.sqrt(1.0/(value*value)-1.0/(maxMeas[chn]*maxMeas[chn])); value = 1.0/Math.sqrt(1.0/(value*value)-1.0/(maxMeas[chn]*maxMeas[chn]));
// value_dx0*=1.0/(value*f*f*f); // value_dx0*=1.0/(value*f*f*f);
// value_dy0*=1.0/(value*f*f*f); // value_dy0*=1.0/(value*f*f*f);
f=value/f; f=value/f;
f*=f*f; f*=f*f;
value_dx0*=f; value_dx0*=f;
...@@ -1891,7 +2030,7 @@ d_s2/d_x0= 2*delta_x*delta_y^2/r2^2 ...@@ -1891,7 +2030,7 @@ d_s2/d_x0= 2*delta_x*delta_y^2/r2^2
this.lMAArrays=calculateJacobianArrays(this.currentfX); this.lMAArrays=calculateJacobianArrays(this.currentfX);
this.currentRMS= calcErrorDiffY(this.currentfX,false); this.currentRMS= calcErrorDiffY(this.currentfX,false);
this.currentRMSPure=calcErrorDiffY(this.currentfX, true); this.currentRMSPure=calcErrorDiffY(this.currentfX, true);
msg=": initial RMS="+IJ.d2s(this.currentRMS,8)+" (pure RMS="+IJ.d2s(this.currentRMSPure,8)+")"+ msg=this.currentStrategyStep+": initial RMS="+IJ.d2s(this.currentRMS,8)+" (pure RMS="+IJ.d2s(this.currentRMSPure,8)+")"+
". Calculating next Jacobian. Points:"+this.dataValues.length+" Parameters:"+this.currentVector.length; ". Calculating next Jacobian. Points:"+this.dataValues.length+" Parameters:"+this.currentVector.length;
if (debugLevel>1) System.out.println(msg); if (debugLevel>1) System.out.println(msg);
if (this.updateStatus) IJ.showStatus(msg); if (this.updateStatus) IJ.showStatus(msg);
...@@ -2023,13 +2162,24 @@ public boolean selectLMAParameters(){ ...@@ -2023,13 +2162,24 @@ public boolean selectLMAParameters(){
// int numSeries=fittingStrategy.getNumSeries(); // int numSeries=fittingStrategy.getNumSeries();
// boolean resetCorrections=false; // boolean resetCorrections=false;
GenericDialog gd = new GenericDialog("Levenberg-Marquardt algorithm parameters for cameras distortions/locations"); GenericDialog gd = new GenericDialog("Levenberg-Marquardt algorithm parameters for cameras distortions/locations");
//TODO: change to selection using series comments
// gd.addNumericField("Fitting series number", this.currentStrategyStep, 0, 3," (-1 - current)");
FieldStrategies fs=fieldFitting.fieldStrategies;
String [] indices=new String[fs.getNumStrategies()+1];
indices[0]="current strategy";
for (int i=0;i<fs.getNumStrategies();i++) {
indices[i+1]=i+": "+fs.getComment(i)+" ("+(fs.isStopAfterThis(i)?"STOP":"CONTINUE")+")";
}
if (this.currentStrategyStep>=(indices.length-1)) this.currentStrategyStep=indices.length-2;
gd.addChoice("Fitting series", indices,indices[this.currentStrategyStep+1]);
gd.addCheckbox("Debug df/dX0, df/dY0", false); gd.addCheckbox("Debug df/dX0, df/dY0", false);
gd.addNumericField("Debug Jacobian for point number", this.debugPoint, 0, 5,"(-1 - none)"); gd.addNumericField("Debug Jacobian for point number", this.debugPoint, 0, 5,"(-1 - none)");
gd.addNumericField("Debug Jacobian for parameter number", this.debugParameter, 0, 5,"(-1 - none)"); gd.addNumericField("Debug Jacobian for parameter number", this.debugParameter, 0, 5,"(-1 - none)");
gd.addCheckbox("Keep current correction parameters (do not reset)", this.keepCorrectionParameters); // gd.addCheckbox("Keep current correction parameters (do not reset)", this.keepCorrectionParameters);
// gd.addNumericField("Iteration number to start (0.."+(numSeries-1)+")", this.seriesNumber, 0); gd.addNumericField("Initial LMA Lambda ", 0.0, 5, 8, "0 - keep, last was "+this.lambda);
gd.addNumericField("Initial LMA Lambda ", this.lambda, 5);
gd.addNumericField("Multiply lambda on success", this.lambdaStepDown, 5); gd.addNumericField("Multiply lambda on success", this.lambdaStepDown, 5);
gd.addNumericField("Threshold RMS to exit LMA", this.thresholdFinish, 7,9,"pix"); gd.addNumericField("Threshold RMS to exit LMA", this.thresholdFinish, 7,9,"pix");
gd.addNumericField("Multiply lambda on failure", this.lambdaStepUp, 5); gd.addNumericField("Multiply lambda on failure", this.lambdaStepUp, 5);
...@@ -2037,48 +2187,44 @@ public boolean selectLMAParameters(){ ...@@ -2037,48 +2187,44 @@ public boolean selectLMAParameters(){
gd.addNumericField("Maximal number of iterations", this.numIterations, 0); gd.addNumericField("Maximal number of iterations", this.numIterations, 0);
gd.addCheckbox("Dialog after each iteration step", this.stopEachStep); gd.addCheckbox("Dialog after each iteration step", this.stopEachStep);
// gd.addCheckbox("Dialog after each iteration series", this.stopEachSeries); gd.addCheckbox("Dialog after each iteration series", this.stopEachSeries);
gd.addCheckbox("Dialog after each failure", this.stopOnFailure); gd.addCheckbox("Dialog after each failure", this.stopOnFailure);
// gd.addCheckbox("Ask for weight function filter", this.askFilter);
gd.addCheckbox("Show modified parameters", this.showParams); gd.addCheckbox("Show modified parameters", this.showParams);
gd.addCheckbox("Show disabled parameters", this.showDisabledParams); gd.addCheckbox("Show disabled parameters", this.showDisabledParams);
gd.addCheckbox("Show per-sample correction parameters", this.showCorrectionParams); gd.addCheckbox("Show per-sample correction parameters", this.showCorrectionParams);
// gd.addCheckbox("Reset all per-sample corrections to zero", resetCorrections); // gd.addCheckbox("Reset all per-sample corrections to zero", resetCorrections);
// gd.addCheckbox("Show debug images before correction",this.showThisImages); // gd.addCheckbox("Show debug images before correction",this.showThisImages);
// gd.addCheckbox("Show debug images after correction", this.showNextImages); // gd.addCheckbox("Show debug images after correction", this.showNextImages);
// gd.addNumericField("Maximal number of threads", this.threadsMax, 0); // gd.addNumericField("Maximal number of threads", this.threadsMax, 0);
// gd.addCheckbox("Use memory-saving/multithreaded version", this.threadedLMA); // gd.addCheckbox("Use memory-saving/multithreaded version", this.threadedLMA);
gd.showDialog(); gd.showDialog();
if (gd.wasCanceled()) return false; if (gd.wasCanceled()) return false;
this.currentStrategyStep= gd.getNextChoiceIndex()-1; //(int) gd.getNextNumber();
if (this.currentStrategyStep>=0){
getStrategy(this.currentStrategyStep);
}
this.debugDerivativesFxDxDy=gd.getNextBoolean(); this.debugDerivativesFxDxDy=gd.getNextBoolean();
debugPoint= (int) gd.getNextNumber(); debugPoint= (int) gd.getNextNumber();
debugParameter= (int) gd.getNextNumber(); debugParameter= (int) gd.getNextNumber();
this.keepCorrectionParameters = gd.getNextBoolean(); // this.keepCorrectionParameters = gd.getNextBoolean();
// this.seriesNumber= (int) gd.getNextNumber(); double preLambda=gd.getNextNumber();
this.lambda= gd.getNextNumber(); if (preLambda>0.0) this.lambda= preLambda;
this.lambdaStepDown= gd.getNextNumber(); this.lambdaStepDown= gd.getNextNumber();
this.thresholdFinish= gd.getNextNumber(); this.thresholdFinish= gd.getNextNumber();
this.lambdaStepUp= gd.getNextNumber(); this.lambdaStepUp= gd.getNextNumber();
this.maxLambda= gd.getNextNumber(); this.maxLambda= gd.getNextNumber();
this.numIterations= (int) gd.getNextNumber(); this.numIterations= (int) gd.getNextNumber();
this.stopEachStep= gd.getNextBoolean(); this.stopEachStep= gd.getNextBoolean();
// this.stopEachSeries= gd.getNextBoolean(); this.stopEachSeries= gd.getNextBoolean();
this.stopOnFailure= gd.getNextBoolean(); this.stopOnFailure= gd.getNextBoolean();
// this.askFilter= gd.getNextBoolean();
this.showParams= gd.getNextBoolean(); this.showParams= gd.getNextBoolean();
this.showDisabledParams= gd.getNextBoolean(); this.showDisabledParams= gd.getNextBoolean();
this.showCorrectionParams= gd.getNextBoolean(); this.showCorrectionParams= gd.getNextBoolean();
// this.showThisImages= gd.getNextBoolean(); // if (!keepCorrectionParameters) fieldFitting.resetSampleCorr();
// this.showNextImages= gd.getNextBoolean();
// this.threadsMax= (int) gd.getNextNumber();
// this.threadedLMA= gd.getNextBoolean();
// resetCorrections= gd.getNextBoolean();
if (!keepCorrectionParameters) fieldFitting.resetSampleCorr();
return true; return true;
} }
...@@ -2778,7 +2924,7 @@ public void listScanQB(){ ...@@ -2778,7 +2924,7 @@ public void listScanQB(){
k_red, k_red,
k_blue, k_blue,
false); false);
double [] best_qb_corr= fieldFitting.getBestQualB( double [] best_qb_corr= fieldFitting.getBestQualB( //best_qb_corr[0] - distance (motorZ)
k_red, k_red,
k_blue, k_blue,
true); true);
...@@ -2908,6 +3054,7 @@ public boolean dialogLMAStep(boolean [] state){ ...@@ -2908,6 +3054,7 @@ public boolean dialogLMAStep(boolean [] state){
GenericDialog gd = new GenericDialog("Levenberg-Marquardt algorithm step"); GenericDialog gd = new GenericDialog("Levenberg-Marquardt algorithm step");
// String [][] parameterDescriptions=fittingStrategy.distortionCalibrationData.parameterDescriptions; // String [][] parameterDescriptions=fittingStrategy.distortionCalibrationData.parameterDescriptions;
gd.addMessage("Current state="+states[iState]); gd.addMessage("Current state="+states[iState]);
gd.addMessage("Current series="+this.currentStrategyStep);
gd.addMessage("Iteration step="+this.iterationStepNumber); gd.addMessage("Iteration step="+this.iterationStepNumber);
gd.addMessage("Initial RMS="+IJ.d2s(this.firstRMS,6)+", Current RMS="+IJ.d2s(this.currentRMS,6)+", new RMS="+IJ.d2s(this.nextRMS,6)); gd.addMessage("Initial RMS="+IJ.d2s(this.firstRMS,6)+", Current RMS="+IJ.d2s(this.currentRMS,6)+", new RMS="+IJ.d2s(this.nextRMS,6));
...@@ -2930,7 +3077,7 @@ public boolean dialogLMAStep(boolean [] state){ ...@@ -2930,7 +3077,7 @@ public boolean dialogLMAStep(boolean [] state){
gd.addNumericField("Maximal number of iterations", this.numIterations, 0); gd.addNumericField("Maximal number of iterations", this.numIterations, 0);
gd.addCheckbox("Dialog after each iteration step", this.stopEachStep); gd.addCheckbox("Dialog after each iteration step", this.stopEachStep);
// gd.addCheckbox("Dialog after each iteration series", this.stopEachSeries); gd.addCheckbox("Dialog after each iteration series", this.stopEachSeries);
gd.addCheckbox("Dialog after each failure", this.stopOnFailure); gd.addCheckbox("Dialog after each failure", this.stopOnFailure);
gd.addCheckbox("Show modified parameters", this.showParams); gd.addCheckbox("Show modified parameters", this.showParams);
gd.addCheckbox("Show disabled parameters", this.showDisabledParams); gd.addCheckbox("Show disabled parameters", this.showDisabledParams);
...@@ -2954,7 +3101,7 @@ public boolean dialogLMAStep(boolean [] state){ ...@@ -2954,7 +3101,7 @@ public boolean dialogLMAStep(boolean [] state){
this.maxLambda= gd.getNextNumber(); this.maxLambda= gd.getNextNumber();
this.numIterations= (int) gd.getNextNumber(); this.numIterations= (int) gd.getNextNumber();
this.stopEachStep= gd.getNextBoolean(); this.stopEachStep= gd.getNextBoolean();
// this.stopEachSeries= gd.getNextBoolean(); this.stopEachSeries= gd.getNextBoolean();
this.stopOnFailure= gd.getNextBoolean(); this.stopOnFailure= gd.getNextBoolean();
this.showParams= gd.getNextBoolean(); this.showParams= gd.getNextBoolean();
this.showDisabledParams= gd.getNextBoolean(); this.showDisabledParams= gd.getNextBoolean();
...@@ -2965,28 +3112,147 @@ public boolean dialogLMAStep(boolean [] state){ ...@@ -2965,28 +3112,147 @@ public boolean dialogLMAStep(boolean [] state){
this.saveSeries=true; this.saveSeries=true;
return gd.wasOKed(); return gd.wasOKed();
} }
public double getAdjustRMS(
FocusingFieldMeasurement measurement,
boolean filterZ,
double z,
double tx,
double ty){
fieldFitting.selectZTilt();
fieldFitting.mechanicalFocusingModel.setZTxTy(z,tx,ty);
double [] sv= fieldFitting.createParameterVector(sagittalMaster);
setDataVector(
false, // calibrate mode
createDataVector(measurement));
if (filterZ) {
boolean [] en=dataWeightsToBoolean();
en= filterByZRanges(
zRanges,
en);
maskDataWeights(en);
prevEnable=en;
int numEn=getNumEnabledSamples(en);
if (numEn<minLeftSamples) return Double.NaN;
}
double [] focusing_fx= createFXandJacobian(sv, false);
double rms_pure= calcErrorDiffY(focusing_fx, true);
// System.out.println("rms_pure="+rms_pure);
return rms_pure;
}
public double findAdjustZ(
FocusingFieldMeasurement measurement,
boolean filterZ,
double zMin,
double zMax,
double zStep,
double tx,
double ty){
double zBest=Double.NaN;
double bestRMS=Double.NaN;
for (double z=zMin;z<=zMax;z+=zStep){
double rms=getAdjustRMS(
measurement,
filterZ,
z,
tx,
ty);
if (((Double.isNaN(bestRMS) || (bestRMS>=rms)) && !Double.isNaN(rms) && (rms>0.0))){
zBest=z;
bestRMS=rms;
}
if (debugLevel>1) System.out.println("findAdjustZ(): z="+z+" rms="+rms);
}
if (debugLevel>0) System.out.println("findAdjustZ()->"+zBest+" (best RMS = "+bestRMS+")");
return zBest;
}
public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ public boolean LevenbergMarquardt(
FocusingFieldMeasurement measurement, // null in calibrate mode
boolean openDialog,
boolean filterZ, // for adjust mode
int debugLevel){
boolean calibrate=measurement==null;
double savedLambda=this.lambda; double savedLambda=this.lambda;
this.debugLevel=debugLevel; this.debugLevel=debugLevel;
if (openDialog && !selectLMAParameters()) return false; if (openDialog && !selectLMAParameters()) return false;
this.startTime=System.nanoTime(); this.startTime=System.nanoTime();
// create savedVector (it depends on parameter masks), restore from it if aborted // create savedVector (it depends on parameter masks), restore from it if aborted
// fieldFitting.initSampleCorrVector(
// flattenSampleCoord(), //double [][] sampleCoordinates,
// getSeriesWeights()); //double [][] sampleSeriesWeights);
// fieldFitting.setEstimatedZ0( z0_estimates, false); // boolean force)
// this.savedVector=this.fieldFitting.createParameterVector(sagittalMaster);
// if (debugDerivativesFxDxDy){
// compareDrDerivatives(this.savedVector);
// }
if (!calibrate) {
this.currentStrategyStep=-1;
fieldFitting.selectZTilt();
keepCorrectionParameters=true;
resetCenter=false;
if (!openDialog) stopEachStep=false;
}
this.iterationStepNumber=0;
this.firstRMS=-1; //undefined
while (true) { // loop for all series
if (this.currentStrategyStep>=0){
if (!getStrategy(this.currentStrategyStep)) break; //invalid strategy
}
if (!keepCorrectionParameters) fieldFitting.resetSampleCorr();
if (resetCenter){
if (debugLevel>0) System.out.println("Resetting center: X "+IJ.d2s(currentPX0,2)+" -> "+IJ.d2s(pX0_distortions,2));
if (debugLevel>0) System.out.println("Resetting center: Y "+IJ.d2s(currentPY0,2)+" -> "+IJ.d2s(pY0_distortions,2));
currentPX0=pX0_distortions;
currentPY0=pY0_distortions;
fieldFitting.setCenterXY(currentPX0,currentPY0);
}
// setDataVector(createDataVector()); //new
fieldFitting.initSampleCorrChnParIndex(flattenSampleCoord());
if (calibrate) {
setDataVector(
true, // calibrate mode
createDataVector()); // Make it different for adjustment mode
fieldFitting.initSampleCorrVector( fieldFitting.initSampleCorrVector(
flattenSampleCoord(), //double [][] sampleCoordinates, flattenSampleCoord(), //double [][] sampleCoordinates,
getSeriesWeights()); //double [][] sampleSeriesWeights); getSeriesWeights()); //double [][] sampleSeriesWeights);
fieldFitting.setEstimatedZ0( z0_estimates, false); // boolean force) fieldFitting.setEstimatedZ0( z0_estimates, false); // boolean force)
} else {
setDataVector(
false, // calibrate mode
createDataVector(measurement)); // Make it different for adjustment mode
if (filterZ) {
boolean [] en=dataWeightsToBoolean();
en= filterByZRanges(
zRanges,
en);
maskDataWeights(en);
prevEnable=en;
int numEn=getNumEnabledSamples(en);
if (numEn<minLeftSamples) return false;
}
fieldFitting.initSampleCorrVector(
flattenSampleCoord(), //double [][] sampleCoordinates,
null); //getSeriesWeights()); //double [][] sampleSeriesWeights);
// fieldFitting.setEstimatedZ0( z0_estimates, false); // boolean force)
}
this.savedVector=this.fieldFitting.createParameterVector(sagittalMaster); this.savedVector=this.fieldFitting.createParameterVector(sagittalMaster);
if (debugDerivativesFxDxDy){ if (debugDerivativesFxDxDy){
compareDrDerivatives(this.savedVector); compareDrDerivatives(this.savedVector);
} }
this.iterationStepNumber=0;
this.firstRMS=-1; //undefined
// while (this.fittingStrategy.isSeriesValid(this.seriesNumber)){ // TODO: Add "stop" tag to series
// while (this.fittingStrategy.isSeriesValid(this.seriesNumber)){ // TODO: Add "stop" tag to series
this.currentVector=null; // invalidate for the new series this.currentVector=null; // invalidate for the new series
// boolean wasLastSeries=false; // boolean wasLastSeries=false;
while (true) { // loop for the same series while (true) { // loop for the same series
boolean [] state=stepLevenbergMarquardtFirst(debugLevel); boolean [] state=stepLevenbergMarquardtFirst(debugLevel);
...@@ -2999,7 +3265,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -2999,7 +3265,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
return false; return false;
} }
if (debugLevel>1) System.out.println(":"+this.iterationStepNumber+": stepLevenbergMarquardtFirst("+debugLevel+")==>"+state[1]+":"+state[0]); if (debugLevel>1) System.out.println(this.currentStrategyStep+":"+this.iterationStepNumber+": stepLevenbergMarquardtFirst("+debugLevel+")==>"+state[1]+":"+state[0]);
boolean cont=true; boolean cont=true;
// Make it success if this.currentRMS<this.firstRMS even if LMA failed to converge // Make it success if this.currentRMS<this.firstRMS even if LMA failed to converge
if (state[1] && !state[0] && (this.firstRMS>this.currentRMS)){ if (state[1] && !state[0] && (this.firstRMS>this.currentRMS)){
...@@ -3010,12 +3276,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3010,12 +3276,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
if ( if (
(this.stopRequested.get()>0) || // graceful stop requested (this.stopRequested.get()>0) || // graceful stop requested
(this.stopEachStep) || (this.stopEachStep) ||
// (this.stopEachSeries && state[1]) || (this.stopEachSeries && state[1]) ||
(this.stopOnFailure && state[1] && !state[0])){ (this.stopOnFailure && state[1] && !state[0])){
if (debugLevel>0){ if (debugLevel>0){
if (this.stopRequested.get()>0) System.out.println("User requested stop"); if (this.stopRequested.get()>0) System.out.println("User requested stop");
System.out.println("LevenbergMarquardt(): step ="+this.iterationStepNumber+ System.out.println("LevenbergMarquardt(): step ="+this.currentStrategyStep+":"+this.iterationStepNumber+
", RMS="+IJ.d2s(this.currentRMS,8)+ ", RMS="+IJ.d2s(this.currentRMS,8)+
" ("+IJ.d2s(this.firstRMS,8)+") "+ " ("+IJ.d2s(this.firstRMS,8)+") "+
") at "+ IJ.d2s(0.000000001*(System.nanoTime()-this.startTime),3)); ") at "+ IJ.d2s(0.000000001*(System.nanoTime()-this.startTime),3));
...@@ -3024,12 +3290,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3024,12 +3290,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
cont=dialogLMAStep(state); cont=dialogLMAStep(state);
this.stopRequested.set(0); // Will not stop each run this.stopRequested.set(0); // Will not stop each run
this.startTime+=(System.nanoTime()-startDialogTime); // do not count time used by the User. this.startTime+=(System.nanoTime()-startDialogTime); // do not count time used by the User.
// if (this.showThisImages) showDiff (this.currentfX, "fit-"+this.iterationStepNumber); // if (this.showThisImages) showDiff (this.currentfX, "fit-"+this.iterationStepNumber);
// if (this.showNextImages) showDiff (this.nextfX, "fit-"+(this.iterationStepNumber+1)); // if (this.showNextImages) showDiff (this.nextfX, "fit-"+(this.iterationStepNumber+1));
} }
stepLevenbergMarquardtAction(debugLevel); // apply step - in any case? stepLevenbergMarquardtAction(debugLevel); // apply step - in any case?
if (this.updateStatus){ if (this.updateStatus){
IJ.showStatus("Step #"+this.iterationStepNumber+ IJ.showStatus("Step #"+this.currentStrategyStep+":"+this.iterationStepNumber+
" RMS="+IJ.d2s(this.currentRMS,8)+ " RMS="+IJ.d2s(this.currentRMS,8)+
" ("+IJ.d2s(this.firstRMS,8)+")"+ " ("+IJ.d2s(this.firstRMS,8)+")"+
" RMSPure="+IJ.d2s(this.currentRMSPure,8)+ " RMSPure="+IJ.d2s(this.currentRMSPure,8)+
...@@ -3041,16 +3307,16 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3041,16 +3307,16 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
savedLambda=this.lambda; savedLambda=this.lambda;
this.savedVector=this.currentVector.clone(); this.savedVector=this.currentVector.clone();
// saveFittingSeries(); // will save series even if it ended in failure, vector will be only updated // saveFittingSeries(); // will save series even if it ended in failure, vector will be only updated
// updateCameraParametersFromCalculated(true); // update camera parameters from all (even disabled) images // updateCameraParametersFromCalculated(true); // update camera parameters from all (even disabled) images
// updateCameraParametersFromCalculated(false); // update camera parameters from enabled only images (may overwrite some of the above) // updateCameraParametersFromCalculated(false); // update camera parameters from enabled only images (may overwrite some of the above)
} }
// if RMS was decreased. this.saveSeries==false after dialogLMAStep(state) only if "cancel" was pressed // if RMS was decreased. this.saveSeries==false after dialogLMAStep(state) only if "cancel" was pressed
commitParameterVector(this.savedVector); // either new or original commitParameterVector(this.savedVector); // either new or original
this.lambda=savedLambda; this.lambda=savedLambda;
return this.saveSeries; // TODO: Maybe change result? return this.saveSeries; // TODO: Maybe change result?
} }
//stepLevenbergMarquardtAction(); //stepLevenbergMarquardtAction();
if (state[1]) { if (state[1]) {
if (!state[0]) { if (!state[0]) {
commitParameterVector(this.savedVector); commitParameterVector(this.savedVector);
...@@ -3058,23 +3324,31 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3058,23 +3324,31 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
return false; // sequence failed return false; // sequence failed
} }
this.savedVector=this.currentVector.clone(); this.savedVector=this.currentVector.clone();
// saveFittingSeries(); // saveFittingSeries();
// updateCameraParametersFromCalculated(true); // update camera parameters from all (even disabled) images // updateCameraParametersFromCalculated(true); // update camera parameters from all (even disabled) images
// updateCameraParametersFromCalculated(false); // update camera parameters from enabled only images (may overwrite some of the above) // updateCameraParametersFromCalculated(false); // update camera parameters from enabled only images (may overwrite some of the above)
// wasLastSeries=this.fittingStrategy.isLastSeries(this.seriesNumber); // wasLastSeries=this.fittingStrategy.isLastSeries(this.seriesNumber);
// this.seriesNumber++; // this.seriesNumber++;
break; // while (true), proceed to the next series break; // while (true), proceed to the next series
} }
} } // while true - same series
// if (wasLastSeries) break; // if (wasLastSeries) break;
// } // while (this.fittingStrategy.isSeriesValid(this.seriesNumber)){ // TODO: Add "stop" tag to series // } // while (this.fittingStrategy.isSeriesValid(this.seriesNumber)){ // TODO: Add "stop" tag to series
if (fieldFitting.fieldStrategies.isLast(this.currentStrategyStep)) break;
String msg="LMA series="+this.currentStrategyStep+ " RMS="+this.currentRMS+" ("+this.firstRMS+") "+
", pure RMS="+this.currentRMSPure+" ("+this.firstRMSPure+") "+
" at "+ IJ.d2s(0.000000001*(System.nanoTime()-this.startTime),3);
if (debugLevel>0) System.out.println("stepLevenbergMarquardtAction() "+msg);
this.currentStrategyStep++;
this.iterationStepNumber=0;
} // for all series
String msg="RMS="+this.currentRMS+" ("+this.firstRMS+") "+ String msg="RMS="+this.currentRMS+" ("+this.firstRMS+") "+
", pure RMS="+this.currentRMSPure+" ("+this.firstRMSPure+") "+ ", pure RMS="+this.currentRMSPure+" ("+this.firstRMSPure+") "+
" at "+ IJ.d2s(0.000000001*(System.nanoTime()-this.startTime),3); " at "+ IJ.d2s(0.000000001*(System.nanoTime()-this.startTime),3);
if (debugLevel>0) System.out.println("stepLevenbergMarquardtAction() "+msg); if (debugLevel>0) System.out.println("stepLevenbergMarquardtAction() "+msg);
// if (this.updateStatus) IJ.showStatus(msg); // if (this.updateStatus) IJ.showStatus(msg);
if (this.updateStatus){ if (this.updateStatus){
IJ.showStatus("Done: Step #"+this.iterationStepNumber+ IJ.showStatus("Done: Step #"+this.currentStrategyStep+":"+this.iterationStepNumber+
" RMS="+IJ.d2s(this.currentRMS,8)+ " RMS="+IJ.d2s(this.currentRMS,8)+
" ("+IJ.d2s(this.firstRMS,8)+")"+ " ("+IJ.d2s(this.firstRMS,8)+")"+
" RMSPure="+IJ.d2s(this.currentRMSPure,8)+ " RMSPure="+IJ.d2s(this.currentRMSPure,8)+
...@@ -3083,8 +3357,9 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3083,8 +3357,9 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
} }
this.savedVector=this.currentVector.clone(); this.savedVector=this.currentVector.clone();
commitParameterVector(this.savedVector); commitParameterVector(this.savedVector);
if (calibrate) zRanges=calcZRanges(dataWeightsToBoolean());
return true; // all series done return true; // all series done
} }
public class FocusingFieldMeasurement{ public class FocusingFieldMeasurement{
public String timestamp; public String timestamp;
...@@ -3327,6 +3602,157 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3327,6 +3602,157 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
e.printStackTrace(); e.printStackTrace();
} }
} }
public void testMeasurement(){
GenericDialog gd = new GenericDialog("Select measurement");
int nMeas=measurements.size()/2;
double zMin=-40.0;
double zMax= 40.0;
double zStep=2.0;
filterZ=true; // (adjustment mode)filter samples by Z
minLeftSamples=10; // minimal number of samples (channel/dir/location) for adjustment
gd.addNumericField("Measurement number",nMeas,0,5,"0.."+(measurements.size()-1));
gd.addCheckbox("Filter samples/channels by Z",filterZ);
gd.addNumericField("Minimal required number of channels/samples",minLeftSamples,0,3,"samples");
gd.addNumericField("Z min",zMin,2,5,"um");
gd.addNumericField("Z max",zMax,2,5,"um");
gd.addNumericField("Z step",zStep,2,5,"um");
gd.showDialog();
if (gd.wasCanceled()) return;
nMeas=(int) gd.getNextNumber();
filterZ=gd.getNextBoolean();
minLeftSamples=(int) gd.getNextNumber();
zMin= gd.getNextNumber();
zMax= gd.getNextNumber();
zStep=gd.getNextNumber();
boolean OK;
if (nMeas>=0){
OK=testMeasurement(
measurements.get(nMeas),
// nMeas,
zMin,
zMax,
zStep);
if (!OK){
if (debugLevel>0) System.out.println("testMeasurement("+nMeas+") failed");
} else {
if (debugLevel>0) System.out.print("======== testMeasurement("+nMeas+") ========");
for (int i=0;i<fieldFitting.mechanicalFocusingModel.paramValues.length;i++){
if ((fieldFitting.mechanicalSelect==null) || fieldFitting.mechanicalSelect[i] ) {
System.out.println(
fieldFitting.mechanicalFocusingModel.getDescription(i)+": "+
IJ.d2s(fieldFitting.mechanicalFocusingModel.paramValues[i],3)+" "+
fieldFitting.mechanicalFocusingModel.getUnits(i));
}
}
}
} else {
for (nMeas=0;nMeas<measurements.size();nMeas++){
if (debugLevel>0) System.out.print("======== testMeasurement("+nMeas+") ======== ");
OK=testMeasurement(
measurements.get(nMeas),
// nMeas,
zMin,
zMax,
zStep);
if (!OK){
if (debugLevel>0) System.out.println("testMeasurement("+nMeas+") failed");
} else {
// if (debugLevel>0) System.out.println("======== testMeasurement("+nMeas+") ========");
for (int i=0;i<fieldFitting.mechanicalFocusingModel.paramValues.length;i++){
if ((fieldFitting.mechanicalSelect==null) || fieldFitting.mechanicalSelect[i] ) {
System.out.println(
fieldFitting.mechanicalFocusingModel.getDescription(i)+": "+
IJ.d2s(fieldFitting.mechanicalFocusingModel.paramValues[i],3)+" "+
fieldFitting.mechanicalFocusingModel.getUnits(i));
}
}
}
}
}
}
public boolean testMeasurement(
FocusingFieldMeasurement measurement, // null in calibrate mode
// int nMeas,
double zMin,
double zMax,
double zStep){
int retryLimit=20;
setDataVector(
false,
createDataVector(measurement)); //measurements.get(nMeas)));
// System.out.println("testMeasurement("+nMeas+")");
double z=findAdjustZ(
// measurements.get(nMeas),
measurement,
filterZ, //boolean filterZ,
zMin,
zMax,
zStep,
0.0, //double tx,
0.0); // double ty);
fieldFitting.mechanicalFocusingModel.setZTxTy(z,0.0,0.0);// z,tx,ty
boolean [] wasPrevEnable=null;
for (int n=0;n<retryLimit;n++) { // TODO: Watch for the mask remain stable
z=fieldFitting.mechanicalFocusingModel.getValue(MECH_PAR.z0);
if (debugLevel>0) System.out.println("testMeasurement(), run "+n+" (z="+z+")");
boolean [] was2PrevEnable=(wasPrevEnable==null)?null:wasPrevEnable.clone();
wasPrevEnable=(prevEnable==null)?null:prevEnable.clone();
boolean OK=LevenbergMarquardt(
measurement,
false, // true, // open dialog
filterZ, // filterZ
debugLevel);
if (!OK){
// if (debugLevel>0) System.out.println("testMeasurement("+nMeas+") failed");
if (debugLevel>1) System.out.println("testMeasurement() failed");
return false;
}
/*
for (int i=0;i<fieldFitting.mechanicalFocusingModel.paramValues.length;i++){
if ((fieldFitting.mechanicalSelect==null) || fieldFitting.mechanicalSelect[i] ) {
System.out.println(
fieldFitting.mechanicalFocusingModel.getDescription(i)+": "+
IJ.d2s(fieldFitting.mechanicalFocusingModel.paramValues[i],3)+" "+
fieldFitting.mechanicalFocusingModel.getUnits(i));
}
}
*/
if ((wasPrevEnable!=null) && (prevEnable!=null) && (wasPrevEnable.length==prevEnable.length)){
boolean changedEnable=false;
for (int i=0;i<prevEnable.length;i++) if (prevEnable[i]!=wasPrevEnable[i]){
changedEnable=true;
break;
}
if (!changedEnable) {
if (debugLevel>0) System.out.println("No filter chnage, finished in "+(n+1)+" steps");
return true;
} else {
if ((was2PrevEnable!=null) && (prevEnable!=null) && (was2PrevEnable.length==prevEnable.length)){
changedEnable=false;
for (int i=0;i<prevEnable.length;i++) if (prevEnable[i]!=was2PrevEnable[i]){
changedEnable=true;
break;
}
if (!changedEnable) {
if (debugLevel>0) System.out.println("Filter repeats one before previous, finished in "+(n+1)+" steps");
return true;
}
}
}
}
}
if (debugLevel>0) System.out.println("Maximal retries exceeded in "+retryLimit+" steps");
return true; //?
}
public class FieldFitting{ public class FieldFitting{
// private Properties savedProperties=null; // private Properties savedProperties=null;
private double [] pXY=null; private double [] pXY=null;
...@@ -3342,6 +3768,11 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3342,6 +3768,11 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
private double [][] sampleCorrCost= new double[6][]; // equivalent cost of one unit of parameter value (in result units, um) private double [][] sampleCorrCost= new double[6][]; // equivalent cost of one unit of parameter value (in result units, um)
private double [][] sampleCorrSigma= new double[6][]; // sigma (in mm) for neighbors influence private double [][] sampleCorrSigma= new double[6][]; // sigma (in mm) for neighbors influence
private double [][] sampleCorrPullZero=new double[6][]; // 1.0 - only difference from neighbors matters, 0.0 - only difference from 0 private double [][] sampleCorrPullZero=new double[6][]; // 1.0 - only difference from neighbors matters, 0.0 - only difference from 0
// private String strategyComment="";
// private boolean lastInSeries=true;
// private double lambda=0.001; // synchronize with top?
public FieldStrategies fieldStrategies;
// private double [] sampleCorrRadius=null; // private double [] sampleCorrRadius=null;
private double [][] sampleCoordinates=null; private double [][] sampleCoordinates=null;
private double [][][][] sampleCorrCrossWeights= new double[6][][][]; private double [][][][] sampleCorrCrossWeights= new double[6][][][];
...@@ -3359,7 +3790,8 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3359,7 +3790,8 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
// private double [] dflt_sampleCorrCost= {0.1,0.5,2.0,1.0}; // private double [] dflt_sampleCorrCost= {0.1,0.5,2.0,1.0};
// private double [] dflt_sampleCorrCost= {0.1,1.0,1.0,0.5}; // private double [] dflt_sampleCorrCost= {0.1,1.0,1.0,0.5};
// private double [] dflt_sampleCorrCost= {0.2,2.0,2.0,1.0,1.0}; // private double [] dflt_sampleCorrCost= {0.2,2.0,2.0,1.0,1.0};
private double [] dflt_sampleCorrCost= {0.1,1.0,1.0,1.0,1.0}; // private double [] dflt_sampleCorrCost= {0.1,1.0,1.0,1.0,1.0};
private double [] dflt_sampleCorrCost= {0.01,1.0,1.0,1.0,1.0};
private double dflt_sampleCorrSigma= 2.0; // mm private double dflt_sampleCorrSigma= 2.0; // mm
private double dflt_sampleCorrPullZero= 0.75; // fraction private double dflt_sampleCorrPullZero= 0.75; // fraction
public final String [] channelDescriptions={ public final String [] channelDescriptions={
...@@ -3411,6 +3843,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3411,6 +3843,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
} }
} }
} }
fieldStrategies.setProperties(prefix+"fieldStrategies.",properties);
} }
public void getProperties(String prefix,Properties properties){ public void getProperties(String prefix,Properties properties){
if (properties.getProperty(prefix+"numberOfLocations")!=null) if (properties.getProperty(prefix+"numberOfLocations")!=null)
...@@ -3536,8 +3969,8 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -3536,8 +3969,8 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
if (debugLevel>1) System.out.println("numberOfLocations==0, can not restore"); if (debugLevel>1) System.out.println("numberOfLocations==0, can not restore");
} }
fieldStrategies= new FieldStrategies(); // reset old
fieldStrategies.getProperties(prefix+"fieldStrategies.",properties);
} }
// public double [] getSampleRadiuses(){ // distance from the current center to each each sample // public double [] getSampleRadiuses(){ // distance from the current center to each each sample
...@@ -4179,7 +4612,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4179,7 +4612,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
public void initSampleCorrVector( public void initSampleCorrVector(
double [][] sampleCoordinates, double [][] sampleCoordinates,
double [][] sampleSeriesWeights){ double [][] sampleSeriesWeights){
System.out.println("initSampleCorrVector()"); if (debugLevel>1) System.out.println("initSampleCorrVector()");
numberOfLocations=sampleCoordinates.length; numberOfLocations=sampleCoordinates.length;
this.sampleCoordinates=new double[sampleCoordinates.length][]; this.sampleCoordinates=new double[sampleCoordinates.length][];
for (int i=0;i<sampleCoordinates.length;i++) this.sampleCoordinates[i]=sampleCoordinates[i].clone(); for (int i=0;i<sampleCoordinates.length;i++) this.sampleCoordinates[i]=sampleCoordinates[i].clone();
...@@ -4250,7 +4683,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4250,7 +4683,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
sampleCorrChnParIndex[nChn]=null; sampleCorrChnParIndex[nChn]=null;
} }
} }
System.out.println("initSampleCorrChnParIndex()"); if (debugLevel>1) System.out.println("initSampleCorrChnParIndex()");
// currently all correction parameters are initialized as zeros. // currently all correction parameters are initialized as zeros.
getCorrVector(); getCorrVector();
} }
...@@ -4297,6 +4730,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4297,6 +4730,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
int distanceParametersNumber, int distanceParametersNumber,
int radialParametersNumber) int radialParametersNumber)
{ {
fieldStrategies= new FieldStrategies();
pXY=new double [2]; pXY=new double [2];
pXY[0]=pX0; pXY[0]=pX0;
pXY[1]=pY0; pXY[1]=pY0;
...@@ -4327,7 +4761,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4327,7 +4761,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
} }
} }
public boolean maskSetDialog(String title){ public boolean maskSetDialog(
String title//,
// String strategyComment,
// double lambda,
// boolean lastInSeries
){
GenericDialog gd = new GenericDialog(title); GenericDialog gd = new GenericDialog(title);
boolean editMechMask=false; boolean editMechMask=false;
boolean editCurvMask=false; boolean editCurvMask=false;
...@@ -4352,7 +4791,13 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4352,7 +4791,13 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
gd.addCheckbox("Setup per-sample correction", setupCorrectionPars); gd.addCheckbox("Setup per-sample correction", setupCorrectionPars);
gd.addCheckbox("Apply same per-sample corrections to all channels", commonCorrectionPars); gd.addCheckbox("Apply same per-sample corrections to all channels", commonCorrectionPars);
gd.addCheckbox("Setup correction parameters when the parameter itself is disabled", disabledCorrectionPars); gd.addCheckbox("Setup correction parameters when the parameter itself is disabled", disabledCorrectionPars);
gd.addMessage("---");
gd.addStringField("Strategy comment",strategyComment,60);
gd.addNumericField("Initial LMA lambda",lambda,3,5,"");
gd.addCheckbox("Reset optical center to distortions center", resetCenter);
gd.addCheckbox("Reset correction parameters before this LMA step", !keepCorrectionParameters);
gd.addCheckbox("Stop after this LMA step", lastInSeries);
// gd.enableYesNoCancel("Keep","Apply"); // default OK (on enter) - "Keep" // gd.enableYesNoCancel("Keep","Apply"); // default OK (on enter) - "Keep"
gd.showDialog(); gd.showDialog();
...@@ -4369,6 +4814,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4369,6 +4814,12 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
setupCorrectionPars=gd.getNextBoolean(); setupCorrectionPars=gd.getNextBoolean();
commonCorrectionPars=gd.getNextBoolean(); commonCorrectionPars=gd.getNextBoolean();
disabledCorrectionPars=gd.getNextBoolean(); disabledCorrectionPars=gd.getNextBoolean();
strategyComment=gd.getNextString();
lambda=gd.getNextNumber();
resetCenter=gd.getNextBoolean();
keepCorrectionParameters=!gd.getNextBoolean();
lastInSeries=gd.getNextBoolean();
// boolean OK; // boolean OK;
if (editMechMask){ if (editMechMask){
boolean [] mask=mechanicalFocusingModel.maskSetDialog("Focusing mechanical parameters mask", mechanicalSelect); boolean [] mask=mechanicalFocusingModel.maskSetDialog("Focusing mechanical parameters mask", mechanicalSelect);
...@@ -4418,6 +4869,21 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4418,6 +4869,21 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
return true; return true;
} }
public void selectZTilt(){
mechanicalSelect=mechanicalFocusingModel.maskSetZTxTy(); // enable z0, tx, ty
// enable all color/dir channels (add separate selection dialog?)
for (int i=0;i<channelSelect.length;i++) {
channelSelect[i]=true;
curvatureSelect[i]=curvatureModel[0].maskAllDisabled();
}
if (sampleCorrSelect!=null){
for (int i=0;i<sampleCorrSelect.length;i++) if (sampleCorrSelect[i]!=null) {
for (int j=0;j<sampleCorrSelect[i].length;j++) sampleCorrSelect[i][j]=false;
}
}
initSampleCorrChnParIndex(flattenSampleCoord());
}
ArrayList<String> getParameterValueStrings(boolean showDisabled, boolean showCorrection){ ArrayList<String> getParameterValueStrings(boolean showDisabled, boolean showCorrection){
ArrayList<String> parList=new ArrayList<String>(); ArrayList<String> parList=new ArrayList<String>();
parList.add("\t ===== Aberrations center =====\t\t"); parList.add("\t ===== Aberrations center =====\t\t");
...@@ -4824,49 +5290,9 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4824,49 +5290,9 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
} }
return chnValues; return chnValues;
} }
/*
public double [] getValsDerivativesOld(
boolean sagittalMaster,
int [] motors, // 3 motor coordinates
double px, // pixel x
double py, // pixel y
double [][] deriv // array of (1..6[][], matching getNumberOfChannels) or null if derivatives are not required
){
double [] motorDerivs=(deriv==null)? null:(new double [mechanicalFocusingModel.getNumPars()]);
double [] chnValues=new double [getNumberOfChannels()];
double mot_z=mechanicalFocusingModel.calc_ZdZ(
motors,
px,
py,
motorDerivs);
int nChn=0;
for (int c=0;c<channelSelect.length;c++) if (channelSelect[c]){
double [] deriv_curv=(deriv==null)?null:(new double [curvatureModel[c].getSize()]);
chnValues[nChn]=curvatureModel[c].getFdF(
null, // param_corr
px,
py,
mot_z,
deriv_curv);
if (deriv!=null){
deriv[nChn]=new double [getNumberOfParameters(sagittalMaster)];
int np=0;
for (int i=0;i<mechanicalFocusingModel.paramValues.length;i++){
if ((mechanicalSelect==null) || mechanicalSelect[i] ) deriv[nChn][np++]=-motorDerivs[i]*deriv_curv[0]; // minus d/dz0 const part
}
for (int n=0;n<channelSelect.length;n++) if (channelSelect[n]){
for (int i=0;i<curvatureSelect[n].length; i++) if (curvatureSelect[n][i] ){
deriv[nChn][np++]=(n==c)?(deriv_curv[i]):0.0;
}
}
}
nChn++;
}
return chnValues;
}
*/
} }
...@@ -4891,7 +5317,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4891,7 +5317,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
{"tx", "horizontal tilt", "um/mm","0.0"}, {"tx", "horizontal tilt", "um/mm","0.0"},
{"ty", "vertical tilt", "um/mm","0.0"}}; {"ty", "vertical tilt", "um/mm","0.0"}};
public double PERIOD=3584.0; // steps/revolution public double PERIOD=3584.0; // steps/revolution
// public double PIXEL_SIZE=0.0022; // mm // public double PIXEL_SIZE=0.0022; // mm
public double [] paramValues=new double [descriptions.length]; public double [] paramValues=new double [descriptions.length];
public MechanicalFocusingModel(){ // add arguments? public MechanicalFocusingModel(){ // add arguments?
...@@ -4921,6 +5347,11 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -4921,6 +5347,11 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
paramValues=new double [descriptions.length]; paramValues=new double [descriptions.length];
for (int i=0;i<vector.length;i++) paramValues[i]=vector[i]; for (int i=0;i<vector.length;i++) paramValues[i]=vector[i];
} }
public void setZTxTy(double z, double tx, double ty){
paramValues[getIndex(MECH_PAR.z0)]=z;
paramValues[getIndex(MECH_PAR.tx)]=tx;
paramValues[getIndex(MECH_PAR.ty)]=ty;
}
public void setVector(double[] vector, boolean [] mask){ public void setVector(double[] vector, boolean [] mask){
for (int i=0;i<vector.length;i++) if (mask[i]) paramValues[i]=vector[i]; for (int i=0;i<vector.length;i++) if (mask[i]) paramValues[i]=vector[i];
...@@ -5035,7 +5466,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5035,7 +5466,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
d2Z/dY/dm3= 0 d2Z/dY/dm3= 0
*/ */
// double [] deriv=new double [paramValues.length]; // double [] deriv=new double [paramValues.length];
double kM1= getValue(MECH_PAR.K0)+getValue(MECH_PAR.KD1)-getValue(MECH_PAR.KD3); double kM1= getValue(MECH_PAR.K0)+getValue(MECH_PAR.KD1)-getValue(MECH_PAR.KD3);
double kM2= getValue(MECH_PAR.K0)-getValue(MECH_PAR.KD1)-getValue(MECH_PAR.KD3); double kM2= getValue(MECH_PAR.K0)-getValue(MECH_PAR.KD1)-getValue(MECH_PAR.KD3);
double kM3= getValue(MECH_PAR.K0)+getValue(MECH_PAR.KD3); double kM3= getValue(MECH_PAR.K0)+getValue(MECH_PAR.KD3);
...@@ -5052,7 +5483,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5052,7 +5483,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
double dx=PIXEL_SIZE*(px-getValue(MECH_PAR.mpX0)); double dx=PIXEL_SIZE*(px-getValue(MECH_PAR.mpX0));
double dy=PIXEL_SIZE*(py-getValue(MECH_PAR.mpY0)); double dy=PIXEL_SIZE*(py-getValue(MECH_PAR.mpY0));
double zx=dx*(getValue(MECH_PAR.tx)+(2*zM3-zM1-zM2)/(4*getValue(MECH_PAR.Lx))) ; double zx=dx*(getValue(MECH_PAR.tx)+(2*zM3-zM1-zM2)/(4*getValue(MECH_PAR.Lx))) ;
// double zy=dy*(getValue(MECH_PAR.ty)+(zM1-zM2)/(2*getValue(MECH_PAR.Ly))); // double zy=dy*(getValue(MECH_PAR.ty)+(zM1-zM2)/(2*getValue(MECH_PAR.Ly)));
double zy=dy*(getValue(MECH_PAR.ty)+(zM2-zM1)/(2*getValue(MECH_PAR.Ly))); double zy=dy*(getValue(MECH_PAR.ty)+(zM2-zM1)/(2*getValue(MECH_PAR.Ly)));
double z=zc+zx+zy; double z=zc+zx+zy;
if (dbg) if ((Math.abs(m1)==debugMot)&& (Math.abs(m2)==debugMot)){ if (dbg) if ((Math.abs(m1)==debugMot)&& (Math.abs(m2)==debugMot)){
...@@ -5077,8 +5508,8 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5077,8 +5508,8 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
double zM2_KD1=-aM2; double zM2_KD1=-aM2;
double zM2_KD3=-aM2; double zM2_KD3=-aM2;
double zM3_K0= aM3; double zM3_K0= aM3;
// double zM3_KD1=-aM3; // double zM3_KD1=-aM3;
// double zM3_KD3= 0.0; // double zM3_KD3= 0.0;
double zM3_KD1= 0.0; double zM3_KD1= 0.0;
double zM3_KD3= aM3; double zM3_KD3= aM3;
double zM1_sM1= kM1*p2pi*Math.sin(m1/p2pi); double zM1_sM1= kM1*p2pi*Math.sin(m1/p2pi);
...@@ -5098,7 +5529,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5098,7 +5529,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
double zc_sM3= 0.5* zM3_sM3; double zc_sM3= 0.5* zM3_sM3;
double zc_cM3= 0.5* zM3_cM3; double zc_cM3= 0.5* zM3_cM3;
// double zx_K0=(2*zM3-zM1-zM2)* dx/(4*getValue(MECH_PAR.Lx)); // double zx_K0=(2*zM3-zM1-zM2)* dx/(4*getValue(MECH_PAR.Lx));
double zx_a=dx/(4*getValue(MECH_PAR.Lx)); double zx_a=dx/(4*getValue(MECH_PAR.Lx));
double zx_K0= (2*zM3_K0-zM1_K0-zM2_K0)*zx_a; double zx_K0= (2*zM3_K0-zM1_K0-zM2_K0)*zx_a;
double zx_KD1=(2*zM3_KD1-zM1_KD1-zM2_KD1)*zx_a; double zx_KD1=(2*zM3_KD1-zM1_KD1-zM2_KD1)*zx_a;
...@@ -5112,7 +5543,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5112,7 +5543,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
double zx_mpX0=dx_mpX0*(getValue(MECH_PAR.tx)+(2*zM3-zM1-zM2)/(4*getValue(MECH_PAR.Lx))); // double zx_mpX0=dx_mpX0/(4*getValue(MECH_PAR.Lx)); double zx_mpX0=dx_mpX0*(getValue(MECH_PAR.tx)+(2*zM3-zM1-zM2)/(4*getValue(MECH_PAR.Lx))); // double zx_mpX0=dx_mpX0/(4*getValue(MECH_PAR.Lx));
double zx_tx= dx; double zx_tx= dx;
double zx_Lx= -dx*(2*zM3-zM1-zM2)/(4*getValue(MECH_PAR.Lx)*getValue(MECH_PAR.Lx)); double zx_Lx= -dx*(2*zM3-zM1-zM2)/(4*getValue(MECH_PAR.Lx)*getValue(MECH_PAR.Lx));
// double zy=dy*(getValue(MECH_PAR.ty)+(zM2-zM1)/(2*getValue(MECH_PAR.Ly))); // double zy=dy*(getValue(MECH_PAR.ty)+(zM2-zM1)/(2*getValue(MECH_PAR.Ly)));
double zy_a=dy/(2*getValue(MECH_PAR.Ly)); double zy_a=dy/(2*getValue(MECH_PAR.Ly));
double zy_K0= (zM2_K0- zM1_K0) *zy_a; double zy_K0= (zM2_K0- zM1_K0) *zy_a;
double zy_KD1= (zM2_KD1-zM1_KD1)*zy_a; double zy_KD1= (zM2_KD1-zM1_KD1)*zy_a;
...@@ -5125,7 +5556,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5125,7 +5556,7 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
double zy_cM3= 0.0; double zy_cM3= 0.0;
double zy_mpY0=dy_mpY0*(getValue(MECH_PAR.ty)+(zM2-zM1)/(2*getValue(MECH_PAR.Ly))); // double zy_mpY0=dy_mpY0/(2*getValue(MECH_PAR.Ly)); double zy_mpY0=dy_mpY0*(getValue(MECH_PAR.ty)+(zM2-zM1)/(2*getValue(MECH_PAR.Ly))); // double zy_mpY0=dy_mpY0/(2*getValue(MECH_PAR.Ly));
double zy_ty= dy; double zy_ty= dy;
// double zy_Ly= -dy*(zM1-zM2)/(2*getValue(MECH_PAR.Ly)*getValue(MECH_PAR.Ly)); // double zy_Ly= -dy*(zM1-zM2)/(2*getValue(MECH_PAR.Ly)*getValue(MECH_PAR.Ly));
double zy_Ly= -dy*(zM2-zM1)/(2*getValue(MECH_PAR.Ly)*getValue(MECH_PAR.Ly)); double zy_Ly= -dy*(zM2-zM1)/(2*getValue(MECH_PAR.Ly)*getValue(MECH_PAR.Ly));
deriv[getIndex(MECH_PAR.K0)]= zc_K0+zx_K0+zy_K0; deriv[getIndex(MECH_PAR.K0)]= zc_K0+zx_K0+zy_K0;
...@@ -5201,13 +5632,21 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){ ...@@ -5201,13 +5632,21 @@ public boolean LevenbergMarquardt(boolean openDialog, int debugLevel){
} }
return mask; return mask;
} }
public boolean [] maskSetZTxTy(){
boolean [] mask = new boolean[this.paramValues.length];
for (int i=0;i<mask.length;i++) mask[i]=false;
mask[getIndex(MECH_PAR.z0)]=true;
mask[getIndex(MECH_PAR.tx)]=true;
mask[getIndex(MECH_PAR.ty)]=true;
return mask;
}
public boolean showModifyParameterValues(String title, boolean showDisabled, boolean [] mask){ public boolean showModifyParameterValues(String title, boolean showDisabled, boolean [] mask){
GenericDialog gd = new GenericDialog(title); GenericDialog gd = new GenericDialog(title);
for (int i=0;i<this.paramValues.length;i++){ for (int i=0;i<this.paramValues.length;i++){
if ((mask==null) || mask[i] ) { if ((mask==null) || mask[i] ) {
gd.addNumericField(getDescription(i),this.paramValues[i],5,8,getUnits(i)); gd.addNumericField(getDescription(i),this.paramValues[i],5,8,getUnits(i));
} else if (showDisabled){ } else if (showDisabled){
// gd.addMessage(getDescription(i) +": "+this.paramValues[i]+" ("+getUnits(i)+")"); // gd.addMessage(getDescription(i) +": "+this.paramValues[i]+" ("+getUnits(i)+")");
gd.addNumericField("(disabled) "+getDescription(i),this.paramValues[i],5,8,getUnits(i)); gd.addNumericField("(disabled) "+getDescription(i),this.paramValues[i],5,8,getUnits(i));
} }
} }
...@@ -5615,6 +6054,11 @@ f_corr: d_fcorr/d_zcorr=0, other: a, reff, kx -> ar[1], ar[2], ar[3], ar[4] ...@@ -5615,6 +6054,11 @@ f_corr: d_fcorr/d_zcorr=0, other: a, reff, kx -> ar[1], ar[2], ar[3], ar[4]
} }
return mask; return mask;
} }
public boolean[] maskAllDisabled(){
boolean [] mask = new boolean[this.modelParams.length*this.modelParams[0].length];
for (int i=0;i<mask.length;i++) mask[i]=false;
return mask;
}
public boolean[] maskSetDialog(String title, boolean detailed, boolean [] currentMask){ public boolean[] maskSetDialog(String title, boolean detailed, boolean [] currentMask){
GenericDialog gd = new GenericDialog(title); GenericDialog gd = new GenericDialog(title);
boolean [] mask = new boolean[this.modelParams.length*this.modelParams[0].length]; boolean [] mask = new boolean[this.modelParams.length*this.modelParams[0].length];
...@@ -5710,6 +6154,608 @@ f_corr: d_fcorr/d_zcorr=0, other: a, reff, kx -> ar[1], ar[2], ar[3], ar[4] ...@@ -5710,6 +6154,608 @@ f_corr: d_fcorr/d_zcorr=0, other: a, reff, kx -> ar[1], ar[2], ar[3], ar[4]
return true; return true;
} }
} }
public boolean getStrategy(int strategyIndex){
FieldStrategies fs=fieldFitting.fieldStrategies;
if ((strategyIndex>=0) && (strategyIndex<fs.getNumStrategies())) {
fs.getFromStrategy( strategyIndex, fieldFitting);
this.strategyComment=fs.getComment(strategyIndex);
this.lambda=fs.getInitialLambda(strategyIndex);
this.lastInSeries=fs.isStopAfterThis(strategyIndex);
this.keepCorrectionParameters=!fs.isResetCorrection(strategyIndex);
this.resetCenter=fs.isResetCenter(strategyIndex);
return true;
} else return false;
}
public int organizeStrategies(String title){
String [] actions={
"<select action>", // 0
"Restore strategy", // 1
"Save (replace) strategy", // 2
"Save (insert before/append) strategy", // 3
"Remove strategy", // 4
"Edit strategy (restore-edit-save)"}; // 5
FieldStrategies fs=fieldFitting.fieldStrategies;
int selectedActionIndex=0;
int selectedStrategyIndex=fs.getNumStrategies();
boolean editStrategy=false;
GenericDialog gd = new GenericDialog(title);
gd.addMessage("Current strategies:");
String [] indices=new String[fs.getNumStrategies()+1];
for (int i=0;i<fs.getNumStrategies();i++) {
indices[i]=i+": "+fs.getComment(i)+
" ("+(fs.isStopAfterThis(i)?"STOP":"CONTINUE")+
(fs.isResetCenter(i)?", RESET CENTER":"")+
(fs.isResetCorrection(i)?", RESET CORRECTIONS":"")+
")";
}
indices[fs.getNumStrategies()]="very end";
for (int i=0;i<fs.getNumStrategies();i++){
gd.addMessage(i+": "+fs.getComment(i)+
" ("+(fs.isStopAfterThis(i)?"STOP":"CONTINUE")+
(fs.isResetCenter(i)?", RESET CENTER":"")+
(fs.isResetCorrection(i)?", RESET CORRECTIONS":"")+
")");
}
gd.addMessage("=======================");
gd.addChoice("Action",actions,actions[selectedActionIndex]);
gd.addChoice("Index", indices,indices[selectedStrategyIndex]);
gd.addMessage("=======================");
gd.addCheckbox("Edit strategy",editStrategy);
gd.enableYesNoCancel("OK","Done");
WindowTools.addScrollBars(gd);
gd.showDialog();
if (gd.wasCanceled()) return -1;
selectedActionIndex=gd.getNextChoiceIndex();
selectedStrategyIndex=gd.getNextChoiceIndex();
editStrategy=gd.getNextBoolean();
if ((selectedActionIndex!=3) && (selectedStrategyIndex>=fs.getNumStrategies())){
selectedStrategyIndex=fs.getNumStrategies()-1; // last
}
if (selectedStrategyIndex>=0){
switch (selectedActionIndex){
case 1:
getStrategy(selectedStrategyIndex);
if (editStrategy){
if (!fieldFitting.maskSetDialog("Setup restored strategy "+selectedStrategyIndex)) break;
}
break;
case 3:
if (editStrategy){
if (!fieldFitting.maskSetDialog("Setup strategy "+selectedStrategyIndex)) break;
}
if (selectedStrategyIndex>=fs.getNumStrategies()) fs.addStrategy();
else fs.insertStrategy(selectedStrategyIndex);
// fall through to the next case
case 2:
if ((selectedActionIndex!=3) && editStrategy){
if (!fieldFitting.maskSetDialog("Setup strategy "+selectedStrategyIndex)) break;
}
fs.setStrategy(selectedStrategyIndex,fieldFitting);
fs.setComment(selectedStrategyIndex,this.strategyComment);
fs.setInitialLambda(selectedStrategyIndex,this.lambda);
fs.setStopAfterThis(selectedStrategyIndex,this.lastInSeries);
fs.setResetCorrection(selectedStrategyIndex,!this.keepCorrectionParameters);
fs.setResetCenter(selectedStrategyIndex,this.resetCenter);
break;
case 4:
fs.removeStrategy(selectedStrategyIndex);
break;
case 0:
if (editStrategy){
if (!fieldFitting.maskSetDialog("Setup current strategy")) break;
}
break;
case 5:
getStrategy(selectedStrategyIndex);
if (!fieldFitting.maskSetDialog("Edit strategy "+selectedStrategyIndex)) break;
fs.setStrategy(selectedStrategyIndex,fieldFitting);
fs.setComment(selectedStrategyIndex,this.strategyComment);
fs.setInitialLambda(selectedStrategyIndex,this.lambda);
fs.setStopAfterThis(selectedStrategyIndex,this.lastInSeries);
fs.setResetCorrection(selectedStrategyIndex,!this.keepCorrectionParameters);
fs.setResetCenter(selectedStrategyIndex,this.resetCenter);
break;
}
}
if (gd.wasOKed()) return 0;
return 1; // "Done" selected
}
public class FieldStrategies{
ArrayList<FieldSrategy> strategies=new ArrayList<FieldSrategy>();
public void setProperties(String prefix,Properties properties){
properties.setProperty(prefix+"strategies_length",strategies.size()+"");
for (int i=0;i<strategies.size();i++){
FieldSrategy strategy=strategies.get(i);
if (strategy!=null) strategy.setProperties(prefix+"strategy_"+i+"_",properties);
}
}
public void getProperties(String prefix,Properties properties){
strategies=new ArrayList<FieldSrategy>();
String s=properties.getProperty(prefix+"strategies_length");
if (s!=null) {
int len=Integer.parseInt(s);
for (int i=0;i<len;i++){
FieldSrategy strategy=new FieldSrategy();
// compatibility with old version
if (properties.getProperty(prefix+"strategy_"+i+"_"+"centerSelect")!=null){
if (debugLevel>0) System.out.println("Restoring new format strategy #"+i);
strategy.getProperties(prefix+"strategy_"+i+"_", properties);
} else if (properties.getProperty(prefix+"_"+i+"_"+"centerSelect")!=null){
if (debugLevel>0) System.out.println("Restoring old format strategy #"+i);
strategy.getProperties(prefix+"_"+i+"_", properties);
} else {
if (debugLevel>0) System.out.println("No info for the field LMA strategy #"+i);
}
strategies.add(strategy);
}
}
}
public int getNumStrategies(){
return strategies.size();
}
public void getFromStrategy( // any of the arguments can be null - do not set this array
int strategyIndex,
FieldFitting fieldFitting){
strategies.get(strategyIndex).getFromStrategy( // any of the arguments can be null - do not set this array
fieldFitting.centerSelect,
fieldFitting.channelSelect,
fieldFitting.mechanicalSelect,
fieldFitting.curvatureSelect,
fieldFitting.sampleCorrSelect,
fieldFitting.sampleCorrCost,
fieldFitting.sampleCorrSigma,
fieldFitting.sampleCorrPullZero
);
}
public void setStrategy( // any of the arguments can be null - do not set this array
int strategyIndex,
FieldFitting fieldFitting){
strategies.get(strategyIndex).setStrategy( // any of the arguments can be null - do not set this array
fieldFitting.centerSelect,
fieldFitting.channelSelect,
fieldFitting.mechanicalSelect,
fieldFitting.curvatureSelect,
fieldFitting.sampleCorrSelect,
fieldFitting.sampleCorrCost,
fieldFitting.sampleCorrSigma,
fieldFitting.sampleCorrPullZero
);
}
public double getInitialLambda(
int strategyIndex) {
return strategies.get(strategyIndex).getInitialLambda();
}
public void setInitialLambda(
int strategyIndex,
double initialLambda) {
strategies.get(strategyIndex).setInitialLambda(initialLambda);
}
public boolean isStopAfterThis(
int strategyIndex) {
return strategies.get(strategyIndex).isStopAfterThis();
}
public boolean isResetCorrection(
int strategyIndex) {
return strategies.get(strategyIndex).isResetCorrection();
}
public boolean isResetCenter(
int strategyIndex) {
return strategies.get(strategyIndex).isResetCenter();
}
public boolean isLast(
int strategyIndex) {
if (strategyIndex < 0) return true;
if (strategyIndex>=(getNumStrategies()-1)) return true;// last
return isStopAfterThis(strategyIndex);
}
public void setStopAfterThis(
int strategyIndex,
boolean stopAfterThis) {
strategies.get(strategyIndex).setStopAfterThis(stopAfterThis);
}
public void setResetCorrection(
int strategyIndex,
boolean resetCorrection) {
strategies.get(strategyIndex).setResetCorrection(resetCorrection);
}
public void setResetCenter(
int strategyIndex,
boolean resetCenter) {
strategies.get(strategyIndex).setResetCenter(resetCenter);
}
public String getComment(
int strategyIndex){
return strategies.get(strategyIndex).getComment();
}
public void setComment(
int strategyIndex,
String comment){
strategies.get(strategyIndex).setComment(comment);
}
public void insertStrategy(
int strategyIndex){
strategies.add(strategyIndex,new FieldSrategy());
}
public void removeStrategy(
int strategyIndex){
strategies.remove(strategyIndex);
}
public void addStrategy(){
strategies.add(new FieldSrategy());
}
public void saveStrategies(
String path, // full path w/o extension or null
String directory ){
String [] patterns= {".fstg-xml",".xml"};
if (path==null) {
path= CalibrationFileManagement.selectFile(true, // save
"Save Field LMA Strategy selection", // title
"Select Field LMA Strategy file", // button
new CalibrationFileManagement.MultipleExtensionsFileFilter(patterns,
"Strategy files (*.fstg-xml)"), // filter
directory); // may be ""
} else path+=patterns[0];
if (path==null) return;
Properties properties=new Properties();
setProperties("",properties); // no prefix
OutputStream os;
try {
os = new FileOutputStream(path);
} catch (FileNotFoundException e1) {
IJ.showMessage("Error","Failed to open field LMA strategy file for writing: "+path);
return;
}
try {
properties.storeToXML(os,
"last updated " + new java.util.Date(), "UTF8");
} catch (IOException e) {
IJ.showMessage("Error","Failed to write XML configuration file: "+path);
return;
}
try {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (debugLevel>0) System.out.println("Field LMA strategy parameters are saved to "+path);
}
public void loadStrategies(
String path, // full path w/o extension or null
String directory ){
String [] patterns= {".fstg-xml",".xml"};
if (path==null) {
path= CalibrationFileManagement.selectFile(false, // save
"Field LMA Strategy selection", // title
"Select Field LMA Strategy file", // button
new CalibrationFileManagement.MultipleExtensionsFileFilter(patterns,
"Strategy files (*.fstg-xml)"), // filter
directory); // may be ""
} else {
// do not add extension if it already exists
if ((path.length()<patterns[0].length()) || (!path.substring(path.length()-patterns[0].length()).equals(patterns[0]))){
path+=patterns[0];
}
}
if (path==null) return;
InputStream is;
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
IJ.showMessage("Error","Failed to open field LMA strategy file: "+path);
return;
}
Properties properties=new Properties();
try {
properties.loadFromXML(is);
} catch (IOException e) {
IJ.showMessage("Error","Failed to read field LMA strategy file: "+path);
return;
}
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
getProperties("",properties); // no prefix
if (debugLevel>0) System.out.println("Field LMA strategy parameters are restored from "+path);
}
class FieldSrategy{
private boolean [] centerSelect=null;
private boolean [] channelSelect=null;
private boolean [] mechanicalSelect=null;
private boolean [][] curvatureSelect=new boolean[6][];
private boolean [][] sampleCorrSelect= new boolean[6][]; // enable individual (per sample coordinates) correction of parameters
private double [][] sampleCorrCost= new double[6][]; // equivalent cost of one unit of parameter value (in result units, um)
private double [][] sampleCorrSigma= new double[6][]; // sigma (in mm) for neighbors influence
private double [][] sampleCorrPullZero=new double[6][]; // 1.0 - only difference from neighbors matters, 0.0 - only difference from 0
// TODO: add LMA-specific (initial lambda, stop after this
private double initialLambda=0.001;
private boolean stopAfterThis=true;
private boolean resetCorrection=false;
private boolean resetCenter=false;
private String strategyComment="";
private Properties properties=null;
private String prefix=null;
public FieldSrategy(){
setDefaults();
}
public FieldSrategy(
String strategyComment,
double lambda,
boolean lastInSeries,
boolean resetCorrection,
boolean resetCenter
){
this.strategyComment=strategyComment;
initialLambda=lambda;
stopAfterThis=lastInSeries;
this.resetCorrection=resetCorrection;
this.resetCenter=resetCenter;
setDefaults();
}
private void setDefaults(){
boolean [][] booleanNull6={null,null,null,null,null,null};
double [][] doubleNull6= {null,null,null,null,null,null};
curvatureSelect= booleanNull6.clone();
sampleCorrSelect= booleanNull6.clone();
sampleCorrCost= doubleNull6.clone();
sampleCorrSigma= doubleNull6.clone();
sampleCorrPullZero= doubleNull6.clone();
}
private String boolToStr(boolean [] ba){
if (ba==null) return "";
String result="";
for (boolean b : ba) result+=b?"+":"-";
return result;
}
private void setPropBool(boolean [] arr, String name){
if (arr!=null) properties.setProperty(prefix+name,boolToStr(arr));
}
private void setPropBool(boolean [][] arr, String name){
if (arr!=null) {
properties.setProperty(prefix+name+"_length",arr.length+"");
for (int i=0;i<arr.length;i++) {
setPropBool(arr[i], name+"_"+i);
}
}
}
private void setPropDouble(double [] arr, String name){
if (arr!=null) properties.setProperty(prefix+name,doubleToStr(arr));
}
private void setPropDouble(double [][] arr, String name){
if (arr!=null) {
properties.setProperty(prefix+name+"_length",arr.length+"");
for (int i=0;i<arr.length;i++) {
setPropDouble(arr[i], name+"_"+i);
}
}
}
private boolean [] strToBool(String s){
if (s==null) return new boolean [0];
boolean [] result= new boolean [s.length()];
for (int i=0;i<result.length;i++) result[i]=(s.charAt(i)=='+');
return result;
}
private String doubleToStr(double [] da){
if (da==null) return "";
String result="";
for (double d : da) result+=","+d;
if (result.length()>0) result=result.substring(1);
return result;
}
private double [] strToDouble(String s){
if (s==null) return new double [0];
String [] sa=s.split(",");
double [] result= new double [sa.length];
for (int i=0;i<result.length;i++) result[i]=Double.parseDouble(sa[i]);
return result;
}
private boolean [] getPropBool(boolean[] arr, String name){
String s=properties.getProperty(prefix+name);
if (s!=null) return strToBool(s);
else return arr;
}
private boolean[][] getPropBool(boolean[][] arr, String name){
if (arr==null){
String s=properties.getProperty(prefix+name+"_length");
if (s==null) return null;
arr=new boolean[Integer.parseInt(s)][];
for (int i=0;i<arr.length;i++) arr[i]=null;
}
for (int i=0;i<arr.length;i++){
boolean [] a=getPropBool((boolean[]) null,name+"_"+i);
if (a!=null) arr[i]=a;
}
return arr;
}
private double [] getPropDouble(double [] arr, String name){
String s=properties.getProperty(prefix+name);
if (s!=null) return strToDouble(s);
else return arr;
}
private double[][] getPropDouble(double[][] arr, String name){
if (arr==null){
String s=properties.getProperty(prefix+name+"_length");
if (s==null) return null;
arr=new double[Integer.parseInt(s)][];
for (int i=0;i<arr.length;i++) arr[i]=null;
}
for (int i=0;i<arr.length;i++){
double [] a=getPropDouble((double []) null,name+"_"+i);
if (a!=null) arr[i]=a;
}
return arr;
}
public String getComment(){
return strategyComment;
}
public void setComment(String comment){
strategyComment=comment;
}
public double getInitialLambda() {
return initialLambda;
}
public void setInitialLambda(double initialLambda) {
this.initialLambda = initialLambda;
}
public boolean isStopAfterThis() {
return stopAfterThis;
}
public void setStopAfterThis(boolean stopAfterThis) {
this.stopAfterThis = stopAfterThis;
}
public boolean isResetCorrection() {
return resetCorrection;
}
public void setResetCorrection(boolean resetCorrection) {
this.resetCorrection = resetCorrection;
}
public boolean isResetCenter() {
return resetCenter;
}
public void setResetCenter(boolean resetCenter) {
this.resetCenter = resetCenter;
}
public void setStrategy( // any of the arguments can be null - do not set this array
boolean [] centerSelect,
boolean [] channelSelect,
boolean [] mechanicalSelect,
boolean [][] curvatureSelect,
boolean [][] sampleCorrSelect,
double [][] sampleCorrCost,
double [][] sampleCorrSigma,
double [][] sampleCorrPullZero
){
if (centerSelect!=null) this.centerSelect= centerSelect.clone();
if (channelSelect!=null) this.channelSelect= channelSelect.clone();
if (mechanicalSelect!=null) this.mechanicalSelect= mechanicalSelect.clone();
if (curvatureSelect!=null) {
this.curvatureSelect= new boolean[curvatureSelect.length][];
for (int i=0;i<curvatureSelect.length;i++) this.curvatureSelect[i]=curvatureSelect[i].clone();
}
if (sampleCorrSelect!=null) {
this.sampleCorrSelect= new boolean[sampleCorrSelect.length][];
for (int i=0;i<sampleCorrSelect.length;i++) this.sampleCorrSelect[i]=sampleCorrSelect[i].clone();
}
if (sampleCorrCost!=null) {
this.sampleCorrCost= new double[sampleCorrCost.length][];
for (int i=0;i<sampleCorrCost.length;i++) this.sampleCorrCost[i]=sampleCorrCost[i].clone();
}
if (sampleCorrSigma!=null) {
this.sampleCorrSigma= new double[sampleCorrSigma.length][];
for (int i=0;i<sampleCorrSigma.length;i++) this.sampleCorrSigma[i]=sampleCorrSigma[i].clone();
}
if (sampleCorrPullZero!=null) {
this.sampleCorrPullZero= new double[sampleCorrPullZero.length][];
for (int i=0;i<sampleCorrPullZero.length;i++) this.sampleCorrPullZero[i]=sampleCorrPullZero[i].clone();
}
}
public void getFromStrategy( // any of the arguments can be null - do not set this array
boolean [] centerSelect,
boolean [] channelSelect,
boolean [] mechanicalSelect,
boolean [][] curvatureSelect,
boolean [][] sampleCorrSelect,
double [][] sampleCorrCost,
double [][] sampleCorrSigma,
double [][] sampleCorrPullZero
){
if (centerSelect!=null) for (int i=0;i<centerSelect.length;i++) centerSelect[i]=this.centerSelect[i];
if (channelSelect!=null) for (int i=0;i<channelSelect.length;i++) channelSelect[i]=this.channelSelect[i];
if (mechanicalSelect!=null) for (int i=0;i<mechanicalSelect.length;i++) mechanicalSelect[i]=this.mechanicalSelect[i];
if (curvatureSelect!=null) {
for (int i=0;i<curvatureSelect.length;i++) curvatureSelect[i]=this.curvatureSelect[i].clone();
}
if (sampleCorrSelect!=null) {
for (int i=0;i<sampleCorrSelect.length;i++) sampleCorrSelect[i]=this.sampleCorrSelect[i].clone();
}
if (sampleCorrCost!=null) {
for (int i=0;i<sampleCorrCost.length;i++) sampleCorrCost[i]=this.sampleCorrCost[i].clone();
}
if (sampleCorrSigma!=null) {
for (int i=0;i<sampleCorrSigma.length;i++) sampleCorrSigma[i]=this.sampleCorrSigma[i].clone();
}
if (sampleCorrPullZero!=null) {
for (int i=0;i<sampleCorrPullZero.length;i++) sampleCorrPullZero[i]=this.sampleCorrPullZero[i].clone();
}
}
public void setProperties(String prefix,Properties properties){
this.prefix=prefix;
this.properties=properties;
setPropBool(centerSelect, "centerSelect");
setPropBool(channelSelect, "channelSelect");
setPropBool(mechanicalSelect, "mechanicalSelect");
setPropBool(curvatureSelect, "curvatureSelect");
setPropBool(sampleCorrSelect, "sampleCorrSelect");
setPropDouble(sampleCorrCost, "sampleCorrCost");
setPropDouble(sampleCorrSigma, "sampleCorrSigma");
setPropDouble(sampleCorrPullZero, "sampleCorrPullZero");
properties.setProperty(prefix+"initialLambda",getInitialLambda()+"");
properties.setProperty(prefix+"stopAfterThis",isStopAfterThis()+"");
properties.setProperty(prefix+"resetCorrection",isResetCorrection()+"");
properties.setProperty(prefix+"resetCenter",isResetCenter()+"");
properties.setProperty(prefix+"strategyComment","<![CDATA["+strategyComment+ "]]>");
}
public void getProperties(String prefix,Properties properties){
this.prefix=prefix;
this.properties=properties;
centerSelect= getPropBool(centerSelect, "centerSelect");
channelSelect= getPropBool(channelSelect, "channelSelect");
mechanicalSelect= getPropBool(mechanicalSelect, "mechanicalSelect");
curvatureSelect= getPropBool(curvatureSelect, "curvatureSelect");
sampleCorrSelect= getPropBool(sampleCorrSelect, "sampleCorrSelect");
sampleCorrCost= getPropDouble(sampleCorrCost, "sampleCorrCost");
sampleCorrSigma= getPropDouble(sampleCorrSigma, "sampleCorrSigma");
sampleCorrPullZero=getPropDouble(sampleCorrPullZero, "sampleCorrPullZero");
String s=properties.getProperty(prefix+"initialLambda");
if (s!=null) initialLambda=Double.parseDouble(s);
s=properties.getProperty(prefix+"stopAfterThis");
if (s!=null) stopAfterThis=Boolean.parseBoolean(s);
s=properties.getProperty(prefix+"resetCorrection");
if (s!=null) resetCorrection=Boolean.parseBoolean(s);
s=properties.getProperty(prefix+"resetCenter");
if (s!=null) resetCenter=Boolean.parseBoolean(s);
s=properties.getProperty(prefix+"strategyComment");
if (s!=null){
strategyComment=s;
if ((strategyComment.length()>10) && strategyComment.substring(0,9).equals("<![CDATA[")) {
strategyComment=strategyComment.substring(9,strategyComment.length()-3);
}
}
}
}
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment