Changeset 4221


Ignore:
Timestamp:
07/22/08 12:40:06 (12 years ago)
Author:
curtis
Message:
  • Split LM curve fitter into separate class.
  • Add option to switch between LM and GA fit algorithms.
Location:
trunk/loci/slim
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/slim/BurnInRenderer.java

    r4216 r4221  
     1// 
     2// BurnInRenderer.java 
     3// 
     4 
     5/* 
     6SLIM Plotter application and curve fitting library for 
     7combined spectral lifetime visualization and analysis. 
     8Copyright (C) 2006-@year@ Curtis Rueden and Eric Kjellman. 
     9 
     10This program is free software; you can redistribute it and/or modify 
     11it under the terms of the GNU General Public License as published by 
     12the Free Software Foundation; either version 3 of the License, or 
     13(at your option) any later version. 
     14 
     15This program is distributed in the hope that it will be useful, 
     16but WITHOUT ANY WARRANTY; without even the implied warranty of 
     17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     18GNU General Public License for more details. 
     19 
     20You should have received a copy of the GNU General Public License 
     21along with this program; if not, write to the Free Software 
     22Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
     23*/ 
     24 
    125package loci.slim; 
    226 
     
    529import loci.slim.CurveFitter; 
    630 
     31/** 
     32 * TODO 
     33 * 
     34 * <dl><dt><b>Source code:</b></dt> 
     35 * <dd><a href="https://skyking.microscopy.wisc.edu/trac/java/browser/trunk/loci/slim/BurnInRenderer.java">Trac</a>, 
     36 * <a href="https://skyking.microscopy.wisc.edu/svn/java/trunk/loci/slim/BurnInRenderer.java">SVN</a></dd></dl> 
     37 * 
     38 * @author Eric Kjellman egkjellma at wisc.edu 
     39 */ 
    740public class BurnInRenderer extends Renderer { 
    841 
    942  protected CurveFitter[][] currentCurves = null; 
    10   protected int currentDim;  
     43  protected int currentDim; 
    1144  protected double[][] image; 
    1245  protected int maxdim; 
    13    
     46 
    1447  public BurnInRenderer(CurveCollection cc) { 
    1548    super(cc); 
     
    3164    numExponentials = 1; 
    3265  } 
    33    
     66 
    3467  public void setComponentCount(int degrees) { 
    3568    image = new double[degrees][maxdim*maxdim]; 
    3669  } 
    37    
     70 
    3871  public void run() { 
    3972    // initial pass - estimates 
     
    91124    return (currentY * (maxdim/currentDim)) + ((maxdim/currentDim) / 2); 
    92125  } 
    93    
     126 
    94127} 
  • trunk/loci/slim/GACurveFitter.java

    r4220 r4221  
    211211   * The array is expected to be of size datapoints 
    212212   **/ 
    213   public void setData(int[] data) throws IllegalArgumentException { 
     213  public void setData(int[] data) { 
    214214    curveData = data; 
    215215  } 
     
    422422   * See getCurve for information about the array to pass. 
    423423   **/ 
    424   public void setCurve(double[][] curve) throws IllegalArgumentException { 
     424  public void setCurve(double[][] curve) { 
    425425    if (curve.length != degrees) { 
    426426      throw new IllegalArgumentException("Incorrect number of degrees."); 
  • trunk/loci/slim/Renderer.java

    r4216 r4221  
     1// 
     2// Renderer.java 
     3// 
     4 
     5/* 
     6SLIM Plotter application and curve fitting library for 
     7combined spectral lifetime visualization and analysis. 
     8Copyright (C) 2006-@year@ Curtis Rueden and Eric Kjellman. 
     9 
     10This program is free software; you can redistribute it and/or modify 
     11it under the terms of the GNU General Public License as published by 
     12the Free Software Foundation; either version 3 of the License, or 
     13(at your option) any later version. 
     14 
     15This program is distributed in the hope that it will be useful, 
     16but WITHOUT ANY WARRANTY; without even the implied warranty of 
     17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     18GNU General Public License for more details. 
     19 
     20You should have received a copy of the GNU General Public License 
     21along with this program; if not, write to the Free Software 
     22Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
     23*/ 
     24 
    125package loci.slim; 
    226 
    3 import loci.slim.CurveCollection; 
    4  
     27/** 
     28 * TODO 
     29 * 
     30 * <dl><dt><b>Source code:</b></dt> 
     31 * <dd><a href="https://skyking.microscopy.wisc.edu/trac/java/browser/trunk/loci/slim/Renderer.java">Trac</a>, 
     32 * <a href="https://skyking.microscopy.wisc.edu/svn/java/trunk/loci/slim/Renderer.java">SVN</a></dd></dl> 
     33 * 
     34 * @author Eric Kjellman egkjellma at wisc.edu 
     35 */ 
    536public abstract class Renderer implements Runnable { 
    637 
     
    1849  protected CurveCollection curveData; 
    1950  protected int numExponentials; 
    20    
     51 
    2152  public abstract void run(); 
    2253 
    2354  public void stop() { 
    24     // TODO: Check if alive and ready? 
    2555    alive = false; 
    2656  } 
     
    3767    return totalIterations; 
    3868  } 
    39    
     69 
    4070  public int getCurrentX() { 
    4171    return currentX; 
     
    5787    return maxProgress; 
    5888  } 
    59    
     89 
    6090  public void setMaxIterations(int mi) { 
    6191    maxIterations = mi; 
     
    73103    return maxRCSE; 
    74104  } 
    75    
     105 
    76106  public abstract double[][] getImage(); 
    77    
     107 
    78108  public void setComponentCount(int degrees) { 
    79109    numExponentials = degrees; 
     
    83113 
    84114  public abstract int getImageY(); 
    85    
     115 
    86116} 
  • trunk/loci/slim/SlimPlotter.java

    r4218 r4221  
    2828package loci.slim; 
    2929 
    30 import jaolho.data.lma.LMA; 
    31 import jaolho.data.lma.LMAFunction; 
    32 import jaolho.data.lma.implementations.JAMAMatrix; 
    3330import java.awt.*; 
    3431import java.awt.datatransfer.*; 
     
    123120  private int numExp; 
    124121  private boolean adjustPeaks, computeFWHMs, cutEnd; 
     122  private boolean useLMA; 
    125123  private boolean[] cVisible; 
    126124  private int maxPeak; 
     
    146144  private JTextField trField, wlField, sField; 
    147145  private JTextField fitField; 
     146  private JRadioButton gaChoice, lmChoice; 
    148147  private JCheckBox peaksBox, fwhmBox, cutBox; 
    149148 
     
    192191  public SlimPlotter(String[] args) throws Exception { 
    193192    console = new OutputConsole("Log"); 
    194     System.setErr(new ConsoleStream(new PrintStream(console))); 
    195193    console.getTextArea().setColumns(54); 
    196194    console.getTextArea().setRows(10); 
     195 
     196    PrintStream err = new PrintStream(console); 
     197 
     198    // HACK - suppress hard-coded exception dumps 
     199    err = LMCurveFitter.filter(err); 
     200 
     201    System.setErr(err); 
    197202 
    198203    // progress estimate: 
     
    287292      paramPane.setBorder(new EmptyBorder(10, 10, 10, 10)); 
    288293      paramDialog.setContentPane(paramPane); 
    289       paramPane.setLayout(new GridLayout(13, 3)); 
     294      paramPane.setLayout(new GridLayout(12, 3)); 
    290295      wField = addRow(paramPane, "Image width", width, "pixels"); 
    291296      hField = addRow(paramPane, "Image height", height, "pixels"); 
     
    300305      ok.addActionListener(this); 
    301306      // row 8 
     307      paramPane.add(new JLabel("Fit algorithm")); 
     308      lmChoice = new JRadioButton("Levenberg-Marquardt"); 
     309      gaChoice = new JRadioButton("Genetic", true); 
     310      ButtonGroup group = new ButtonGroup(); 
     311      group.add(lmChoice); 
     312      group.add(gaChoice); 
     313      paramPane.add(lmChoice); 
     314      paramPane.add(gaChoice); 
     315      // row 9, column 1 
    302316      peaksBox = new JCheckBox("Align peaks", true); 
    303317      peaksBox.setToolTipText("<html>Computes the peak of each spectral " + 
     
    308322        "perform exponential curve fitting.</html>"); 
    309323      paramPane.add(peaksBox); 
    310       paramPane.add(new JLabel()); 
    311       paramPane.add(new JLabel()); 
    312       // row 9 
     324      // row 9, column 2 
    313325      fwhmBox = new JCheckBox("Compute FWHMs", false); 
    314326      fwhmBox.setToolTipText( 
    315327        "<html>Computes the full width half max at each channel.</html>"); 
    316328      paramPane.add(fwhmBox); 
    317       paramPane.add(new JLabel()); 
    318       paramPane.add(new JLabel()); 
    319       // row 10 
     329      // row 9, column 3 
    320330      cutBox = new JCheckBox("Cut 1.5ns from fit", true); 
    321331      cutBox.setToolTipText("<html>When performing exponential curve " + 
     
    324334        "sometimes drops off unexpectedly, skewing<br>the fit results.</html>"); 
    325335      paramPane.add(cutBox); 
     336      // row 10 
     337      paramPane.add(new JLabel()); 
    326338      paramPane.add(new JLabel()); 
    327339      paramPane.add(new JLabel()); 
    328340      // row 11 
    329       paramPane.add(new JLabel()); 
    330       paramPane.add(new JLabel()); 
    331       paramPane.add(new JLabel()); 
    332       // row 12 
    333341      paramPane.add(new JLabel()); 
    334342      paramPane.add(ok); 
     
    10851093        waveStep = parse(sField.getText(), waveStep); 
    10861094        numExp = parse(fitField.getText(), numExp); 
     1095        useLMA = lmChoice.isSelected(); 
    10871096        adjustPeaks = peaksBox.isSelected(); 
    10881097        computeFWHMs = fwhmBox.isSelected(); 
     
    12541263        tau = new float[channels][numExp]; 
    12551264        for (int c=0; c<channels; c++) Arrays.fill(tau[c], Float.NaN); 
    1256         ExpFunction func = new ExpFunction(numExp); 
    1257         float[] params = new float[2 * numExp + 1]; 
    1258         if (numExp == 1) { 
    1259           //params[0] = maxVal; 
    1260           params[1] = picoToBins(1000); 
    1261           params[2] = 0; 
    1262         } 
    1263         else if (numExp == 2) { 
    1264           //params[0] = maxVal / 2; 
    1265           params[1] = picoToBins(800); 
    1266           //params[2] = maxVal / 2; 
    1267           params[3] = picoToBins(2000); 
    1268           params[4] = 0; 
    1269         } 
    12701265        int num = timeBins - maxPeak; 
    12711266 
     
    12771272        } 
    12781273 
    1279         float[] xVals = new float[num]; 
    1280         for (int i=0; i<num; i++) xVals[i] = i; 
    1281         float[] yVals = new float[num]; 
    1282         float[] weights = new float[num]; 
    1283         Arrays.fill(weights, 1); // no weighting 
    12841274        StringBuffer equation = new StringBuffer(); 
    12851275        equation.append("y(t) = "); 
     
    13021292          log("\tChannel #" + (c + 1) + ":"); 
    13031293 
    1304           /* 
    1305           // CTR - BEGIN NOR CODE 
    1306           GACurveFitter fitter = new GACurveFitter(); 
     1294          CurveFitter fitter; 
     1295          if (useLMA) fitter = new LMCurveFitter(); 
     1296          else fitter = new GACurveFitter(); 
    13071297          for (int i=0; i<num; i++) { 
    13081298            data[i] = (int) samps[timeBins * cc + maxPeak + i]; 
     
    13111301          fitter.setData(data); 
    13121302          fitter.estimate(); 
    1313           for (int i=0; i<1500; i++) fitter.iterate(); 
     1303          for (int i=0; i<100; i++) fitter.iterate(); 
    13141304          double[][] results = fitter.getCurve(); 
    13151305          log("\t\tchi2=" + fitter.getReducedChiSquaredError()); 
     
    13191309            tau[c][i] = binsToPico((float) (1 / results[i][1])); 
    13201310            log("\t\t" + TAU + (i + 1) + "=" + tau[c][i] + " ps"); 
    1321             log("\t\tc=" + results[i][2]); 
    1322           } 
     1311          } 
     1312          log("\t\tc=" + results[0][2]); 
    13231313          fitResults[c] = new double[2 * numExp + 1]; 
    13241314          for (int i=0; i<numExp; i++) { 
     
    13281318          } 
    13291319          fitResults[c][2 * numExp] = results[0][2]; 
    1330           // CTR - END NOR CODE 
    1331           */ 
    1332  
    1333           // CTR - BEGIN LMA CODE 
    1334           System.arraycopy(samps, timeBins * cc + maxPeak, yVals, 0, num); 
    1335           LMA lma = null; 
    1336           for (int i=0; i<numExp; i++) { 
    1337             int e = 2 * i; 
    1338             params[e] = maxVals[cc] / numExp; 
    1339           } 
    1340           lma = new LMA(func, params, new float[][] {xVals, yVals}, 
    1341             weights, new JAMAMatrix(params.length, params.length)); 
    1342           lma.fit(); 
    1343           log("\t\titerations=" + lma.iterationCount); 
    1344           // normalize chi2 by the channel's peak value 
    1345           if (maxVals[cc] != 0) lma.chi2 /= maxVals[cc]; 
    1346           // scale chi2 by degrees of freedom 
    1347           lma.chi2 /= num - params.length; 
    1348           log("\t\tchi2=" + lma.chi2); 
    1349           for (int i=0; i<numExp; i++) { 
    1350             int e = 2 * i; 
    1351             log("\t\ta" + (i + 1) + "=" + 
    1352               (100 * lma.parameters[e] / maxVals[cc]) + "%"); 
    1353             tau[c][i] = binsToPico((float) (1 / lma.parameters[e + 1])); 
    1354             log("\t\t" + TAU + (i + 1) + "=" + tau[c][i] + " ps"); 
    1355           } 
    1356           log("\t\tc=" + lma.parameters[2 * numExp]); 
    1357           fitResults[c] = lma.parameters; 
    1358           // CTR - END LMA CODE 
    13591320 
    13601321          setProgress(progress, ++p); 
     
    17151676 
    17161677  /** 
    1717    * A summed exponential function of the form: 
    1718    * y(t) = a1*e^(-b1*t) + ... + an*e^(-bn*t) + c. 
    1719    */ 
    1720   public class ExpFunction extends LMAFunction { 
    1721     /** Number of exponentials to fit. */ 
    1722     private int numExp = 1; 
    1723  
    1724     /** Constructs a function with the given number of summed exponentials. */ 
    1725     public ExpFunction(int num) { numExp = num; } 
    1726  
    1727     public double getY(double x, double[] a) { 
    1728       double sum = 0; 
    1729       for (int i=0; i<numExp; i++) { 
    1730         int e = 2 * i; 
    1731         sum += a[e] * Math.exp(-a[e + 1] * x); 
    1732       } 
    1733       sum += a[2 * numExp]; 
    1734       return sum; 
    1735     } 
    1736  
    1737     public double getPartialDerivate(double x, double[] a, int parameterIndex) { 
    1738       if (parameterIndex == 2 * numExp) return 1; // c 
    1739       int e = parameterIndex / 2; 
    1740       int off = parameterIndex % 2; 
    1741       switch (off) { 
    1742         case 0: 
    1743           return Math.exp(-a[e + 1] * x); // a 
    1744         case 1: 
    1745           return -a[e] * x * Math.exp(-a[e + 1] * x); // b 
    1746       } 
    1747       throw new RuntimeException("No such parameter index: " + 
    1748         parameterIndex); 
    1749     } 
    1750   } 
    1751  
    1752   /** 
    1753    * HACK - OutputStream extension for filtering out hardcoded 
    1754    * RuntimeException.printStackTrace() exceptions within LMA library. 
    1755    */ 
    1756   public class ConsoleStream extends PrintStream { 
    1757     private boolean ignore; 
    1758  
    1759     public ConsoleStream(OutputStream out) { 
    1760       super(out); 
    1761     } 
    1762  
    1763     public void println(String s) { 
    1764       if (s.equals("java.lang.RuntimeException: Matrix is singular.")) { 
    1765         ignore = true; 
    1766       } 
    1767       else if (ignore && !s.startsWith("\tat ")) ignore = false; 
    1768       if (!ignore) super.println(s); 
    1769     } 
    1770  
    1771     public void println(Object o) { 
    1772       String s = o.toString(); 
    1773       println(s); 
    1774     } 
    1775   } 
    1776  
    1777   /** 
    17781678   * Helper class for clipboard interaction, stolen from 
    17791679   * <a href="http://www.javapractices.com/Topic82.cjp">Java Practices</a>. 
Note: See TracChangeset for help on using the changeset viewer.