1 package jalview.ws2.operations;
3 import static java.lang.String.format;
4 import java.io.IOException;
7 import java.util.function.Consumer;
9 import jalview.analysis.SeqsetUtils;
10 import jalview.analysis.SeqsetUtils.SequenceInfo;
11 import jalview.api.AlignViewportI;
12 import jalview.bin.Cache;
13 import jalview.commands.RemoveGapsCommand;
14 import jalview.datamodel.Alignment;
15 import jalview.datamodel.AlignmentAnnotation;
16 import jalview.datamodel.AlignmentI;
17 import jalview.datamodel.AlignmentView;
18 import jalview.datamodel.HiddenColumns;
19 import jalview.datamodel.SeqCigar;
20 import jalview.datamodel.SequenceI;
21 import jalview.gui.AlignFrame;
22 import jalview.io.JnetAnnotationMaker;
23 import jalview.util.MessageManager;
24 import jalview.ws.params.ArgumentI;
25 import jalview.ws2.WSJob;
26 import jalview.ws2.WSJobStatus;
27 import jalview.ws2.operations.AlignmentWorker.AlignmentJob;
29 public class JPredWorker extends AbstractPollableWorker
32 private class InputFormatParameter implements ArgumentI
37 public String getName()
43 public String getValue()
49 public void setValue(String selectedItem)
55 private static class JobInput
61 Map<String, SequenceInfo> sequenceInfo;
64 public class JPredJob extends WSJob
70 Map<String, SequenceInfo> sequenceInfo;
74 super(operation.service.getProviderName(), operation.getName(),
75 operation.getHostName());
78 private void setInput(JobInput input)
81 delMap = input.delMap;
82 sequenceInfo = input.sequenceInfo;
86 public class PredictionResult
90 HiddenColumns hiddenCols;
94 public AlignmentI getAlignment()
99 public HiddenColumns getHiddenCols()
105 private JPredOperation operation;
107 private Consumer<PredictionResult> resultConsumer;
109 private AlignmentView view;
111 private WSJobList<JPredJob> jobs = new WSJobList<>();
113 private JPredJob job;
115 private char gapChar;
117 AlignmentI currentView;
119 public JPredWorker(JPredOperation operation, AlignmentView alignView,
120 AlignViewportI viewport)
122 this.operation = operation;
123 this.view = alignView;
124 this.gapChar = viewport.getGapCharacter();
125 this.currentView = viewport.getAlignment();
129 public Operation getOperation()
135 public WSJobList<? extends WSJob> getJobs()
140 public void setResultConsumer(Consumer<PredictionResult> consumer)
142 this.resultConsumer = consumer;
146 public void start() throws IOException
148 var input = prepareInputData(view, true);
149 job = new JPredJob();
152 listeners.fireJobCreated(job);
154 var formatArg = new InputFormatParameter();
155 formatArg.setValue(input.msf.size() > 1 ? "fasta" : "seq");
156 List<ArgumentI> args = List.of(formatArg);
157 int exceptionCount = MAX_RETRY;
163 jobId = operation.getWebService().submit(job.msf, args);
164 } catch (IOException e)
166 Cache.log.warn(format("%s failed to submit sequences to the server %s.",
167 operation.getName(), operation.getHostName()), e);
170 } while (jobId == null && exceptionCount > 0);
174 job.setStatus(WSJobStatus.SUBMITTED);
175 listeners.fireWorkerStarted();
179 job.setStatus(WSJobStatus.SERVER_ERROR);
180 listeners.fireWorkerNotStarted();
184 private static JobInput prepareInputData(AlignmentView view, boolean viewOnly)
186 SeqCigar[] msf = view.getSequences();
187 SequenceI seq = msf[0].getSeq('-');
190 delMap = view.getVisibleContigMapFor(seq.gapMap());
191 SequenceI[] aln = new SequenceI[msf.length];
192 for (int i = 0; i < msf.length; i++)
193 aln[i] = msf[i].getSeq('-');
194 var sequenceInfo = msf.length > 1 ? SeqsetUtils.uniquify(aln, true)
195 : Map.of("Sequence", SeqsetUtils.SeqCharacterHash(seq));
198 // Remove hidden regions from sequence objects.
199 String seqs[] = view.getSequenceStrings('-');
200 for (int i = 0; i < msf.length; i++)
201 aln[i].setSequence(seqs[i]);
202 seq.setSequence(seqs[0]);
204 var input = new JobInput();
205 input.msf = List.of(aln);
206 input.delMap = delMap;
207 input.sequenceInfo = sequenceInfo;
214 listeners.fireWorkerCompleting();
215 PredictionResult result = null;
218 result = (job.msf.size() > 1)
219 ? prepareMultipleSequenceResult(job)
220 : prepareSingleSequenceResult(job);
221 } catch (Exception e)
223 Cache.log.error("Couldn't retrieve results for job.", e);
224 job.setStatus(WSJobStatus.SERVER_ERROR);
228 for (var annot : result.alignment.getAlignmentAnnotation())
230 if (annot.sequenceRef != null)
232 replaceAnnotationOnAlignmentWith(annot, annot.label,
233 getClass().getName(), annot.sequenceRef);
237 resultConsumer.accept(result);
238 listeners.fireWorkerCompleted();
241 private PredictionResult prepareMultipleSequenceResult(JPredJob job)
244 AlignmentI alignment;
245 HiddenColumns hiddenCols = null;
246 var prediction = operation.predictionSupplier.getPrediction(job);
247 if (job.delMap != null)
249 Object[] alandcolsel = view.getAlignmentAndHiddenColumns(gapChar);
250 alignment = new Alignment((SequenceI[]) alandcolsel[0]);
251 hiddenCols = (HiddenColumns) alandcolsel[1];
255 alignment = operation.predictionSupplier.getAlignment(job);
256 var seqs = new SequenceI[alignment.getHeight()];
257 for (int i = 0; i < alignment.getHeight(); i++)
259 seqs[i] = alignment.getSequenceAt(i);
261 SeqsetUtils.deuniquify(job.sequenceInfo, seqs);
264 alignment.setDataset(currentView.getDataset());
265 JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, false,
267 var result = new PredictionResult();
268 result.alignment = alignment;
269 result.hiddenCols = hiddenCols;
270 result.firstSeq = firstSeq;
274 static final int msaIndex = 0;
276 private PredictionResult prepareSingleSequenceResult(JPredJob job)
279 var prediction = operation.predictionSupplier.getPrediction(job);
280 AlignmentI alignment = new Alignment(prediction.getSeqsAsArray());
281 HiddenColumns hiddenCols = null;
282 int firstSeq = prediction.getQuerySeqPosition();
283 if (job.delMap != null)
285 Object[] alanndcolsel = view.getAlignmentAndHiddenColumns(gapChar);
286 SequenceI[] seqs = (SequenceI[]) alanndcolsel[0];
287 new RemoveGapsCommand(MessageManager.getString("label.remove_gaps"),
288 new SequenceI[] { seqs[msaIndex] }, currentView);
289 SequenceI profileSeq = alignment.getSequenceAt(firstSeq);
290 profileSeq.setSequence(seqs[msaIndex].getSequenceAsString());
292 SeqsetUtils.SeqCharacterUnhash(alignment.getSequenceAt(firstSeq),
293 job.sequenceInfo.get("Sequence"));
294 alignment.setDataset(currentView.getDataset());
295 JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, true,
297 SequenceI profileSeq = alignment.getSequenceAt(0);
298 if (job.delMap != null)
300 hiddenCols = alignment.propagateInsertions(profileSeq, view);
302 var result = new PredictionResult();
303 result.alignment = alignment;
304 result.hiddenCols = hiddenCols;
305 result.firstSeq = firstSeq;
309 private static void replaceAnnotationOnAlignmentWith(
310 AlignmentAnnotation newAnnot, String typeName, String calcId,
313 SequenceI dsseq = aSeq.getDatasetSequence();
314 while (dsseq.getDatasetSequence() != null)
316 dsseq = dsseq.getDatasetSequence();
318 // look for same annotation on dataset and lift this one over
319 List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
321 if (dsan != null && dsan.size() > 0)
323 for (AlignmentAnnotation dssan : dsan)
325 dsseq.removeAlignmentAnnotation(dssan);
328 AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
329 dsseq.addAlignmentAnnotation(dssan);
330 dssan.adjustForAlignment();