View Javadoc
1   package com.github.celldynamics.quimp;
2   
3   import java.io.File;
4   import java.io.FileNotFoundException;
5   import java.io.IOException;
6   
7   import org.slf4j.Logger;
8   import org.slf4j.LoggerFactory;
9   
10  import com.github.celldynamics.quimp.BOAState.BOAp;
11  import com.github.celldynamics.quimp.filesystem.DataContainer;
12  import com.github.celldynamics.quimp.filesystem.FileExtensions;
13  import com.github.celldynamics.quimp.filesystem.versions.Converter170202;
14  import com.github.celldynamics.quimp.utils.QuimpToolsCollection;
15  
16  /**
17   * This class override most of methods from super class QParams. The goal of this class is rather
18   * not to extend QParams but to use polymorphism to provide requested data to callers keeping
19   * compatibility with old QuimP architecture. The QuimP uses QParams to keep parameters read from
20   * configuration files (<i>paQP</i>, <i>snQP</i>) and then to provide some of parameters stored in
21   * these files to local configuration classes such as e.g.
22   * {@link com.github.celldynamics.quimp.plugin.ecmm.ECMp},
23   * {@link com.github.celldynamics.quimp.plugin.qanalysis.Q_Analysis},
24   * {@link com.github.celldynamics.quimp.plugin.ana.ANAp}. QuimP supports two independent file
25   * formats:
26   * <ol>
27   * <li>based on separate files (old QuimP) such as case_cellno.paQP
28   * <li>compound <i>case.QCONF</i> that contains data for all cells
29   * </ol>
30   * Many of parameters in underlying class QParams are set to be private and they are accessible by
31   * setters and getters. Many setter/getter are overridden in this class and contains simple logic to
32   * provide requested and expected data even if the source file was <i>QCONF</i>. There is also
33   * method that convert parameters read from QCONF and fills underlying fields in QParams.
34   * Appropriate object either QParam or QParamsQconf is created upon configuration file type. Owing
35   * to Java late binding, always correct method is called even if the object is casted to QParams
36   * 
37   * @author p.baniukiewicz
38   *
39   */
40  public class QParamsQconf extends QParams {
41  
42    /**
43     * The Constant LOGGER.
44     */
45    static final Logger LOGGER = LoggerFactory.getLogger(QParamsQconf.class.getName());
46    private Serializer<DataContainer> loaded; // instance of loaded data
47    private File newParamFile;
48    /**
49     * Currently processed handler.
50     * 
51     * <p>This is compatibility parameter. Old QuimP uses separated files for every snake thus QParams
52     * contained always correct values as given snake has been loaded. New QuimP uses composed file
53     * and this field points to currently processed Handler and it must be controlled from outside.
54     * For compatibility reasons all setters and getters assumes that there is only one Handler (as
55     * in old QuimP). This field allow to set current Handler if QParamsEschange instance is used.
56     */
57    private int currentHandler;
58  
59    /**
60     * Instantiates a new q params qconf.
61     */
62    public QParamsQconf() {
63  
64    }
65  
66    /**
67     * Set default values for superclass, also prefix and path for files.
68     * 
69     * @param p <i>QCONF</i> file with extension
70     */
71    public QParamsQconf(File p) {
72      super(p);
73      currentHandler = 0;
74      newParamFile = p;
75      // prepare correct name for old parameters
76      super.setParamFile(new File(QuimpToolsCollection
77              .removeExtension(newParamFile.getParent() + File.separator + newParamFile.getName())
78              + "_" + currentHandler + FileExtensions.configFileExt));
79      paramFormat = QParams.NEW_QUIMP;
80    }
81  
82    /**
83     * Get configuration file (with path).
84     * 
85     * @return the newParamFile
86     */
87    @Override
88    public File getParamFile() {
89      return newParamFile;
90    }
91  
92    /**
93     * Get name of configuration file.
94     * 
95     * @return the prefix. Without any cell number in contrary to super.getFileName(). Only filename
96     *         without path and extension.
97     */
98    @Override
99    public String getFileName() {
100     return QuimpToolsCollection.removeExtension(newParamFile.getName());
101   }
102 
103   /**
104    * Extract DataContainer from Serializer super class.
105    * 
106    * @return the loadedDataContainer
107    */
108   public DataContainer getLoadedDataContainer() {
109     return loaded.obj;
110   }
111 
112   /**
113    * Return file creation date and other parameters.
114    * 
115    * @return QuimpVersion structure
116    */
117   public QuimpVersion getFileVersion() {
118     return loaded.timeStamp;
119   }
120 
121   /**
122    * Read composite <i>QCONF</i> file.
123    * 
124    * <p>Update <tt>outputFileCore</tt> in {@link BOAp} to current QCONF.
125    * 
126    * @throws QuimpException when problem with loading/parsing JSON
127    */
128   @Override
129   public void readParams() throws QuimpException {
130     Serializer<DataContainer> s = new Serializer<>(DataContainer.class, QuimP.TOOL_VERSION);
131     s.registerConverter(new Converter170202<>(QuimP.TOOL_VERSION));
132     try {
133       // load file and make first check of correctness
134       loaded = s.load(getParamFile()); // try to load
135       // restore qstate because some methods still need it
136       BOA_.qState = getLoadedDataContainer().getBOAState();
137       // update path and file core name
138       if (getLoadedDataContainer().getBOAState() != null) {
139         getLoadedDataContainer().getBOAState().boap
140                 .setOutputFileCore(newParamFile.getAbsolutePath());
141       }
142     } catch (Exception e) { // stop on fail (file or json error)
143       LOGGER.debug(e.getMessage(), e);
144       throw new QuimpException(
145               "Loading or processing of " + getParamFile().getAbsolutePath() + " failed", e);
146     }
147     // second check of basic logic
148     // checking against nulls is in Serializer
149     if (!loaded.className.equals("DataContainer") || !loaded.timeStamp.getName().equals("QuimP")
150             && !loaded.timeStamp.getName().equals(QuimpToolsCollection.defNote)) {
151       LOGGER.debug("Not QuimP file?");
152       throw new QuimpException(
153               "Loaded file " + getParamFile().getAbsolutePath() + " is not QuimP file");
154     }
155     compatibilityLayer(); // fill underlying data (paQP) from QCONF
156   }
157 
158   /**
159    * Sets the active handler.
160    *
161    * @param num the new active handler
162    */
163   public void setActiveHandler(int num) {
164     currentHandler = num;
165     compatibilityLayer();
166   }
167 
168   /**
169    * Gets the active handler.
170    *
171    * @return the active handler
172    */
173   public int getActiveHandler() {
174     return currentHandler;
175   }
176 
177   /**
178    * Write all parameters in new format.
179    * 
180    * <p>Makes pure dump what means that object is already packed with QuimP format. Used when
181    * original data has been loaded, modified and then they must be saved again under the same
182    * name.
183    * 
184    * @throws IOException When file can not be saved
185    */
186   @Override
187   public void writeParams() throws IOException {
188     LOGGER.debug("New file format: Updating data " + getParamFile());
189     try {
190       // loaded.obj.beforeSerialize(); // call explicitly beforeSerialize because Dump doesn't
191       // do
192       // Serializer.Dump(loaded, getParamFile(), BOA_.qState.boap.savePretty); // "loaded" is
193       // already
194       // packed by
195       // Serializer
196       Serializer<DataContainer> n;
197       n = new Serializer<>(getLoadedDataContainer(), QuimP.TOOL_VERSION);
198       if (getLoadedDataContainer().BOAState.boap.savePretty) {
199         // configured
200         n.setPretty();
201       }
202       n.save(getParamFile().getAbsolutePath());
203       n = null;
204     } catch (FileNotFoundException e) {
205       LOGGER.error("File " + getParamFile() + " could not be saved. " + e.getMessage());
206       LOGGER.debug(e.getMessage(), e);
207       throw new IOException("File " + getParamFile() + " could not be saved. ", e);
208     }
209   }
210 
211   /**
212    * Fill some underlying fields to assure compatibility between new and old formats.
213    * 
214    * <p><b>Warning</b>
215    * 
216    * <p>Some data depend on status of <tt>currentHandler</tt> that points to current outline. This
217    * is
218    * due to differences in file handling between old format (separate paQP for every cell) and new
219    * (one file).
220    */
221   private void compatibilityLayer() {
222     // fill underlying parameters
223     super.setParamFile(new File(QuimpToolsCollection.removeExtension(newParamFile.getAbsolutePath())
224             + "_" + currentHandler + FileExtensions.configFileExt));
225     super.guessOtherFileNames();
226     super.setSnakeQP(getSnakeQP());
227     super.setStatsQP(getStatsQP());
228     if (getLoadedDataContainer().getBOAState() != null) {
229       super.setSegImageFile(getLoadedDataContainer().getBOAState().boap.getOrgFile());
230       super.setImageScale(getLoadedDataContainer().getBOAState().boap.getImageScale());
231       super.setFrameInterval(getLoadedDataContainer().getBOAState().boap.getImageFrameInterval());
232       super.nmax = getLoadedDataContainer().getBOAState().boap.NMAX;
233       super.deltaT = getLoadedDataContainer().getBOAState().boap.delta_t;
234       super.maxIterations = getLoadedDataContainer().getBOAState().segParam.max_iterations;
235       super.setNodeRes(getLoadedDataContainer().getBOAState().segParam.getNodeRes());
236       super.setBlowup(getLoadedDataContainer().getBOAState().segParam.blowup);
237       super.sampleTan = getLoadedDataContainer().getBOAState().segParam.sample_tan;
238       super.sampleNorm = getLoadedDataContainer().getBOAState().segParam.sample_norm;
239       super.velCrit = getLoadedDataContainer().getBOAState().segParam.vel_crit;
240       super.centralForce = getLoadedDataContainer().getBOAState().segParam.f_central;
241       super.contractForce = getLoadedDataContainer().getBOAState().segParam.f_contract;
242       super.frictionForce = getLoadedDataContainer().getBOAState().boap.f_friction;
243       super.imageForce = getLoadedDataContainer().getBOAState().segParam.f_image;
244       super.sensitivity = getLoadedDataContainer().getBOAState().boap.sensitivity;
245       super.finalShrink = getLoadedDataContainer().getBOAState().segParam.finalShrink;
246       // set frames from snakes
247       super.setStartFrame(getLoadedDataContainer().getBOAState().nest.getHandler(currentHandler)
248               .getStartFrame());
249       super.setEndFrame(
250               getLoadedDataContainer().getBOAState().nest.getHandler(currentHandler).getEndFrame());
251       if (getLoadedDataContainer().getEcmmState() != null) {
252         super.setStartFrame(
253                 getLoadedDataContainer().getEcmmState().oHs.get(currentHandler).getStartFrame());
254         super.setEndFrame(
255                 getLoadedDataContainer().getEcmmState().oHs.get(currentHandler).getEndFrame());
256       }
257       // fill only if ANA has been run
258       if (getLoadedDataContainer().getANAState() != null) {
259         super.cortexWidth =
260                 getLoadedDataContainer().getANAState().aS.get(currentHandler).getCortexWidthScale();
261 
262         // copy here is due to #204 - when new tiff is added to old loaded fluTiffs,
263         // previous absolute paths / are extended to full: /xxx/yyy/Quimp
264         File[] lf = getLoadedDataContainer().getANAState().aS.get(currentHandler).fluTiffs;
265         this.fluTiffs = new File[lf.length];
266         fluTiffs[0] = new File(lf[0].getPath());
267         fluTiffs[1] = new File(lf[1].getPath());
268         fluTiffs[2] = new File(lf[2].getPath());
269       }
270 
271     }
272   }
273 
274   /**
275    * Write parameter file paQP in old format (QuimP11).
276    * 
277    * @throws IOException
278    * 
279    */
280   public void writeOldParams() throws IOException {
281     super.writeParams();
282   }
283 
284   /*
285    * (non-Javadoc)
286    * 
287    * In old way this was related always to loaded file that was separate for every snake. In new
288    * way this field should not exist stand alone
289    * 
290    * @see com.github.celldynamics.quimp.QParams#getStartFrame()
291    * 
292    */
293   @Override
294   public int getStartFrame() {
295     return super.getStartFrame();
296   }
297 
298   /*
299    * (non-Javadoc)
300    * 
301    * In old way this was related always to loaded file that was separate for every snake. In new
302    * way this field should not exist stand alone
303    * 
304    * @see com.github.celldynamics.quimp.QParams#setStartFrame(int)
305    * 
306    */
307   @Override
308   public void setStartFrame(int startFrame) {
309     super.setStartFrame(startFrame); // backward compatibility
310     getLoadedDataContainer().getBOAState().nest.getHandler(currentHandler).startFrame = startFrame;
311   }
312 
313   /*
314    * (non-Javadoc)
315    * 
316    * In old way this was related always to loaded file that was separate for every snake. In new
317    * way this field should not exist stand alone
318    * 
319    * @see com.github.celldynamics.quimp.QParams#getEndFrame()
320    */
321   @Override
322   public int getEndFrame() {
323     return super.getEndFrame();
324   }
325 
326   /*
327    * (non-Javadoc)
328    * 
329    * In old way this was related always to loaded file that was separate for every snake. In new
330    * way this field should not exist stand alone
331    * 
332    * @see com.github.celldynamics.quimp.QParams#setEndFrame(int)
333    */
334   @Override
335   public void setEndFrame(int endFrame) {
336     super.setEndFrame(endFrame);
337     getLoadedDataContainer().getBOAState().nest.getHandler(currentHandler).endFrame = endFrame;
338   }
339 
340   /*
341    * (non-Javadoc)
342    * 
343    * @see com.github.celldynamics.quimp.QParams#getImageScale()
344    */
345   @Override
346   public double getImageScale() {
347     return super.getImageScale();
348   }
349 
350   /*
351    * (non-Javadoc)
352    * 
353    * @see com.github.celldynamics.quimp.QParams#setImageScale(double)
354    */
355   @Override
356   public void setImageScale(double imageScale) {
357     getLoadedDataContainer().getBOAState().boap.setImageScale(imageScale);
358     super.setImageScale(imageScale);
359   }
360 
361   /*
362    * (non-Javadoc)
363    * 
364    * @see com.github.celldynamics.quimp.QParams#getFrameInterval()
365    */
366   @Override
367   public double getFrameInterval() {
368     return super.getFrameInterval();
369   }
370 
371   /*
372    * (non-Javadoc)
373    * 
374    * @see com.github.celldynamics.quimp.QParams#setFrameInterval(double)
375    */
376   @Override
377   public void setFrameInterval(double frameInterval) {
378     getLoadedDataContainer().getBOAState().boap.setImageFrameInterval(frameInterval);
379     super.setFrameInterval(frameInterval);
380   }
381 
382   /**
383    * Return Nest object.
384    * 
385    * @return {@link Nest} object from loaded dataset.
386    */
387   public Nest getNest() {
388     if (getLoadedDataContainer() != null) {
389       return getLoadedDataContainer().getBOAState().nest;
390     } else {
391       return null;
392     }
393   }
394 
395   /*
396    * (non-Javadoc)
397    * 
398    * @see com.github.celldynamics.quimp.QParams#getBlowup()
399    */
400   @Override
401   public int getBlowup() {
402     return super.getBlowup();
403   }
404 
405   /*
406    * (non-Javadoc)
407    * 
408    * @see com.github.celldynamics.quimp.QParams#setBlowup(int)
409    */
410   @Override
411   public void setBlowup(int blowup) {
412     getLoadedDataContainer().getBOAState().segParam.blowup = blowup;
413     super.setBlowup(blowup);
414   }
415 
416   /*
417    * (non-Javadoc)
418    * 
419    * @see com.github.celldynamics.quimp.QParams#getNodeRes()
420    */
421   @Override
422   public double getNodeRes() {
423     return super.getNodeRes();
424   }
425 
426   /*
427    * (non-Javadoc)
428    * 
429    * @see com.github.celldynamics.quimp.QParams#setNodeRes(int)
430    */
431   @Override
432   public void setNodeRes(double nodeRes) {
433     getLoadedDataContainer().getBOAState().segParam.setNodeRes(nodeRes);
434     super.setNodeRes(nodeRes);
435   }
436 
437   /**
438    * For new file format it redirects call to super class searching for old files (paQP).
439    * 
440    * <p>Finally old files can be processed together with new one.
441    * 
442    * @return Array of found files.
443    * @see com.github.celldynamics.quimp.QParams#findParamFiles()
444    */
445   @Override
446   public File[] findParamFiles() {
447     return super.findParamFiles();
448   }
449 
450   /**
451    * Create fake snQP name, for compatibility reasons.
452    * 
453    * @return theoretical name of snQP file which is used then to estimate names of map files by
454    *         com.github.celldynamics.quimp.Qp class. This name contains \a suffix already
455    * @see com.github.celldynamics.quimp.QParams#getSnakeQP()
456    */
457   @Override
458   public File getSnakeQP() {
459     String path = getParamFile().getParent();
460     String file = QuimpToolsCollection.removeExtension(getParamFile().getName());
461     return new File(
462             path + File.separator + file + "_" + currentHandler + FileExtensions.snakeFileExt);
463   }
464 
465   /*
466    * (non-Javadoc)
467    * 
468    * @see com.github.celldynamics.quimp.QParams#getStatsQP()
469    * 
470    * @see com.github.celldynamics.quimp.QParamsQconf.getSnakeQP()
471    */
472   @Override
473   public File getStatsQP() {
474     String path = getParamFile().getParent();
475     String file = QuimpToolsCollection.removeExtension(getParamFile().getName());
476     return new File(
477             path + File.separator + file + "_" + currentHandler + FileExtensions.statsFileExt);
478   }
479 
480 }