/*
* Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fhcrc.cpl.viewer.align;
import org.apache.log4j.Logger;
import org.fhcrc.cpl.toolbox.ApplicationContext;
import org.fhcrc.cpl.toolbox.datastructure.Pair;
import org.fhcrc.cpl.toolbox.statistics.RInterface;
import org.fhcrc.cpl.toolbox.filehandler.TempFileManager;
import java.io.*;
/**
* Spline-based alignment algorithm
*
*
*/
public class SplineAligner extends Aligner
{
private static Logger _log = Logger.getLogger(SplineAligner.class);
// 20 is pretty darn high. Lower values may
//be more appropriate in most cases. 20 is for backward compatibility.
public static final int DEFAULT_DEGREES_OF_FREEDOM = 20;
//This controls, technically speaking, how squiggly the alignment gets.
//Higher numbers -> more squiggly.
protected int degreesOfFreedom = DEFAULT_DEGREES_OF_FREEDOM;
protected boolean copiedRCode = false;
public SplineAligner()
{
}
/**
* Cover method. In the absence of filename information, use a filename that's
* likely to be unique
* @param pairs
* @param maxValueToWarp
* @return
*/
public double[] alignPairs(Pair<Double,Double>[] pairs, int maxValueToWarp)
{
return alignPairs(pairs, maxValueToWarp, "length" + pairs.length);
}
/**
* Generic method for creating a warping based on pairs of values.
* Create temp files with names based on tempFileNameStart, in case the user
* wants to peruse them
* @param pairs
* @param maxValueToWarp
* @return
*/
public double[] alignPairs(Pair<Double,Double>[] pairs, double maxValueToWarp,
String tempFileNameStart)
{
_log.debug("alignPairs. Pairs: " + pairs.length + ", max to warp: " +
maxValueToWarp + ", DoF: " + degreesOfFreedom);
PrintWriter pw = null;
double[] result = null;
if (pairs.length < 4)
throw new RuntimeException("SplineAligner.alignPairs: at least 4 pairs are necessary for alignment, only " +
pairs.length + " were provided");
File pairsFile = null;
try
{
if (!copiedRCode)
{
copyRCode();
copiedRCode = true;
}
String pairFileName = tempFileNameStart + ".pairs.tsv";
pairsFile = writePairsFile(pairs, pairFileName);
File outFile = TempFileManager.createTempFile(tempFileNameStart + ".align_out.tsv", this);
File rScriptFile = TempFileManager.createTempFile(tempFileNameStart + ".align.R", this);
pw = new PrintWriter(new FileOutputStream(rScriptFile));
pw.println("source('warp_scans.R')");
String line = "map_file_scans_onto_file('" +
pairFileName + "', '" +
outFile.getName() + "', maxScan=" + maxValueToWarp + ", df=" +
degreesOfFreedom + ");";
pw.println(line);
pw.flush();
pw.close();
RInterface.runRScript(rScriptFile, this);
result = parseWarpingMap(outFile, (int) maxValueToWarp);
// if (buildCharts)
// createChart(pairs, result);
}
catch (Exception x)
{
ApplicationContext.errorMessage("Failed alignment: " + x.getMessage(), x);
TempFileManager.unmarkFileForDeletion(pairsFile, this);
TempFileManager.deleteTempFiles(this);
return null;
}
finally
{
if (pw != null)
pw.close();
}
return result;
}
/**
* copy warp_scans.R to the temp directory
* @throws IOException
* @throws FileNotFoundException
*/
protected void copyRCode() throws IOException, FileNotFoundException
{
InputStream in = SplineAligner.class.getResourceAsStream("warp_scans.R");
File alignFile = TempFileManager.createTempFile("warp_scans.R", this);
OutputStream out = new FileOutputStream(alignFile);
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0)
out.write(buf, 0, len);
in.close();
out.close();
if (!alignFile.exists())
throw new FileNotFoundException("Failed to copy R code to temp directory");
}
/**
* Generic code for parsing a map of integers to doubles
* @param mapFile
* @return
* @throws IOException
* @throws FileNotFoundException
*/
public double[] parseWarpingMap(File mapFile, int maxValueToWarp)
throws IOException, FileNotFoundException
{
double[] warpingMap = new double[maxValueToWarp + 1];
BufferedReader br =
new BufferedReader(new InputStreamReader(new FileInputStream(mapFile)));
while (true)
{
String line = br.readLine();
if (line == null) break;
if (line.startsWith("source_scan"))
continue;
String[] sourceAndDest = line.split("\t");
warpingMap[Integer.parseInt(sourceAndDest[0])] =
Double.parseDouble(sourceAndDest[1]);
}
return warpingMap;
}
/**
* Write a file containing pairs
* @param fileName
* @throws FileNotFoundException
*/
protected File writePairsFile(Pair<Double,Double>[] pairs, String fileName)
throws FileNotFoundException
{
File currentPairsFile =
TempFileManager.createTempFile(fileName,
this);
PrintWriter currentPairsPW = new PrintWriter(currentPairsFile);
currentPairsPW.println("source\tdest");
for (Pair<Double,Double> pair : pairs)
currentPairsPW.println(pair.first + "\t" + pair.second);
currentPairsPW.flush();
_log.debug("wrote feature pairs to file " + currentPairsFile.getAbsolutePath());
return currentPairsFile;
}
public int getDegreesOfFreedom()
{
return degreesOfFreedom;
}
public void setDegreesOfFreedom(int degreesOfFreedom)
{
this.degreesOfFreedom = degreesOfFreedom;
}
}