001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.align;
022
023
024import org.biojava.nbio.structure.Atom;
025import org.biojava.nbio.structure.Structure;
026import org.biojava.nbio.structure.StructureTools;
027import org.biojava.nbio.structure.align.ce.ConfigStrucAligParams;
028import org.biojava.nbio.structure.align.client.PdbPair;
029import org.biojava.nbio.structure.align.model.AFPChain;
030import org.biojava.nbio.structure.align.util.AtomCache;
031import org.biojava.nbio.structure.align.util.SynchronizedOutFile;
032import org.biojava.nbio.structure.align.xml.AFPChainXMLConverter;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import java.io.File;
037import java.io.FileOutputStream;
038import java.io.OutputStreamWriter;
039import java.util.concurrent.Callable;
040import java.util.zip.GZIPOutputStream;
041
042/**
043 * Simple Callable Class that calculates a pairwise alignment in a different
044 * thread, so that multiple pairwise alignments can be run in parallel
045 * (examples: all-to-all alignments, DB search alignments).
046 * Adapted to a more general implementation since 4.1.0, because before it
047 * was thought for DB search only.
048 *
049 * @author Aleix Lafita
050 */
051public class CallableStructureAlignment implements  Callable<AFPChain> {
052
053        private final static Logger logger = LoggerFactory.getLogger(
054                        CallableStructureAlignment.class);
055
056        //Structure information
057        private PdbPair pair;
058        private AtomCache cache;
059        private Atom[] ca1;
060        private Atom[] ca2;
061
062        //File output information - for DB searches
063        private SynchronizedOutFile outFile;
064        private File outFileDir;
065
066        //Algorithm information
067        private String algorithmName;
068        private ConfigStrucAligParams params;
069
070        /**
071         * Default constructor. Used in DB search.
072         * Instantiates an empty object, everything has to be set independently.
073         */
074        public CallableStructureAlignment() {}
075
076        /**
077         * Constructor for all-to-all alignment calculation.
078         * Used for MultipleMC seed alignment calculation, for example.
079         *
080         * @param ca1 Atoms to align of the first structure
081         * @param ca2 Atoms to align of the second structure
082         * @param algorithmName the pairwise aligner algorithm to use, a new
083         *                      instance will be created for each thread.
084         * @param params parameter bean for the alignment.
085         */
086        public CallableStructureAlignment(Atom[] ca1, Atom[] ca2, String algorithmName, ConfigStrucAligParams params){
087                this.ca1 = ca1;
088                this.ca2 = ca2;
089                this.algorithmName = algorithmName;
090                this.params = params;
091        }
092
093        @Override
094        public AFPChain call() throws Exception {
095
096                //Prepare the alignment algorithm
097                StructureAlignment algorithm = StructureAlignmentFactory.getAlgorithm(algorithmName);
098                if (params!=null) algorithm.setParameters(params);
099
100                AFPChain afpChain = null;
101                try {
102                        //Download the Atoms if they are not provided from the outisde (DB searches usually)
103                        if (ca1 == null) {
104                                Structure structure1 = cache.getStructure(pair.getName1());
105                                ca1 =  StructureTools.getRepresentativeAtomArray(structure1);
106                        } else ca1 = StructureTools.cloneAtomArray(ca1);
107
108                        Structure structure2 = null;
109                        if (ca2 == null) {
110                                structure2 = cache.getStructure(pair.getName2());
111                                ca2 = StructureTools.getRepresentativeAtomArray(structure2);
112                        } else ca2 = StructureTools.cloneAtomArray(ca2);
113
114                        afpChain = algorithm.align(ca1, ca2);
115
116                        if (pair!=null){
117                                afpChain.setName1(pair.getName1());
118                                afpChain.setName2(pair.getName2());
119                        }
120
121                        //Do not output anything if there is no File information
122                        if (outFile != null && outFileDir != null){
123                                String desc2 = structure2.getPDBHeader().getDescription();
124                                if ( desc2 == null)
125                                        desc2="";
126                                afpChain.setDescription2(desc2);
127                                String result = afpChain.toDBSearchResult();
128                                logger.info("{}", result);
129
130                                outFile.write(result);
131
132                                String xml = AFPChainXMLConverter.toXML(afpChain, ca1, ca2);
133                                writeXML(outFileDir,pair.getName1(), pair.getName2(), xml);
134                        }
135
136                } catch ( Exception e){
137                        logger.error("Exception: ", e);
138                }
139                return afpChain;
140        }
141
142        public PdbPair getPair() {
143                return pair;
144        }
145
146        public void setPair(PdbPair pair) {
147                this.pair = pair;
148        }
149
150        public AtomCache getCache() {
151                return cache;
152        }
153
154        public void setCache(AtomCache cache) {
155                this.cache = cache;
156        }
157
158        public SynchronizedOutFile getOutFile() {
159                return outFile;
160        }
161
162        public void setOutFile(SynchronizedOutFile outFile) {
163                this.outFile = outFile;
164        }
165
166        public Atom[] getCa1() {
167                return ca1;
168        }
169
170        public void setCa1(Atom[] ca1) {
171                this.ca1 = ca1;
172        }
173
174        private void writeXML(File outFileF, String name1, String name2, String xml)
175        {
176                try{
177                        // Create file
178                        File newF = new File(outFileF, "dbsearch_" +name1+"_" + name2+".xml.gz");
179
180                        FileOutputStream fstream = new FileOutputStream(newF);
181
182                        GZIPOutputStream gz = new GZIPOutputStream(fstream);
183                        OutputStreamWriter writer = new OutputStreamWriter(gz);
184                        writer.write(xml);
185                        writer.close();
186                } catch (Exception e){//Catch exception if any
187                        logger.error("Exception: ", e);
188                }
189        }
190
191        public void setOutputDir(File outFileF) {
192                this.outFileDir = outFileF;
193        }
194
195        public void setAlgorithmName(String algorithmName) {
196                this.algorithmName = algorithmName;
197        }
198
199        public void setParameters(ConfigStrucAligParams parameters) {
200                this.params = parameters;
201        }
202}