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"),
289 { seqs[msaIndex] }, currentView);
290 SequenceI profileSeq = alignment.getSequenceAt(firstSeq);
291 profileSeq.setSequence(seqs[msaIndex].getSequenceAsString());
293 SeqsetUtils.SeqCharacterUnhash(alignment.getSequenceAt(firstSeq),
294 job.sequenceInfo.get("Sequence"));
295 alignment.setDataset(currentView.getDataset());
296 JnetAnnotationMaker.add_annotation(prediction, alignment, firstSeq, true,
298 SequenceI profileSeq = alignment.getSequenceAt(0);
299 if (job.delMap != null)
301 hiddenCols = alignment.propagateInsertions(profileSeq, view);
303 var result = new PredictionResult();
304 result.alignment = alignment;
305 result.hiddenCols = hiddenCols;
306 result.firstSeq = firstSeq;
310 private static void replaceAnnotationOnAlignmentWith(
311 AlignmentAnnotation newAnnot, String typeName, String calcId,
314 SequenceI dsseq = aSeq.getDatasetSequence();
315 while (dsseq.getDatasetSequence() != null)
317 dsseq = dsseq.getDatasetSequence();
319 // look for same annotation on dataset and lift this one over
320 List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
322 if (dsan != null && dsan.size() > 0)
324 for (AlignmentAnnotation dssan : dsan)
326 dsseq.removeAlignmentAnnotation(dssan);
329 AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
330 dsseq.addAlignmentAnnotation(dssan);
331 dssan.adjustForAlignment();