1 package jalview.ws2.actions.secstructpred;
3 import java.io.IOException;
6 import jalview.analysis.AlignSeq;
7 import jalview.analysis.AlignmentAnnotationUtils;
8 import jalview.analysis.SeqsetUtils;
9 import jalview.analysis.SeqsetUtils.SequenceInfo;
10 import jalview.api.AlignViewportI;
11 import jalview.bin.Console;
12 import jalview.commands.RemoveGapsCommand;
13 import jalview.datamodel.Alignment;
14 import jalview.datamodel.AlignmentAnnotation;
15 import jalview.datamodel.AlignmentI;
16 import jalview.datamodel.AlignmentView;
17 import jalview.datamodel.SeqCigar;
18 import jalview.datamodel.SequenceI;
19 import jalview.io.JPredFile;
20 import jalview.io.JnetAnnotationMaker;
21 import jalview.util.Comparison;
22 import jalview.util.MessageManager;
23 import jalview.ws.params.ArgumentI;
24 import jalview.ws2.actions.BaseJob;
25 import jalview.ws2.actions.BaseTask;
26 import jalview.ws2.actions.ServiceInputInvalidException;
27 import jalview.ws2.api.Credentials;
28 import jalview.ws2.api.JobStatus;
29 import jalview.ws2.client.api.SecStructPredWebServiceClientI;
31 public class SecStructPredPDBSearchTask extends
32 BaseTask<SecStructPredPDBSearchTask.SecStructPredJob, AlignmentI>
34 private final SecStructPredWebServiceClientI client;
36 private final AlignmentView alignmentView;
37 private final AlignmentI currentView;
38 private final char gapChar;
40 SecStructPredPDBSearchTask(SecStructPredWebServiceClientI client,
41 List<ArgumentI> args, Credentials credentials,
42 AlignViewportI viewport)
44 super(client, args, credentials);
46 this.alignmentView = viewport.getAlignmentView(true);
47 this.currentView = viewport.getAlignment();
48 this.gapChar = viewport.getGapCharacter();
52 protected List<SecStructPredJob> prepareJobs()
53 throws ServiceInputInvalidException
55 SeqCigar[] msf = alignmentView.getSequences();
56 SequenceI seq = msf[0].getSeq('-');
57 int[] delMap = alignmentView.getVisibleContigMapFor(seq.gapMap());
59 throw new ServiceInputInvalidException(MessageManager.getString(
60 "error.implementation_error_multiple_single_sequence_prediction_jobs_not_supported"));
61 var seqInfo = SeqsetUtils.SeqCharacterHash(seq);
62 seq.setSequence(AlignSeq.extractGaps(Comparison.GapChars,
63 alignmentView.getASequenceString('-', 0)));
64 if (seq.getLength() < 20)
65 throw new ServiceInputInvalidException(
66 "Sequence is too short to predict with JPred - need at least 20 amino acids.");
67 var job = new SecStructPredJob(seq, delMap, seqInfo);
68 job.setStatus(JobStatus.READY);
72 public static final int MSA_INDEX = 0;
75 protected AlignmentI collectResult(List<SecStructPredJob> jobs)
78 var job = jobs.get(0); // There should be exactly one job
79 var status = job.getStatus();
81 String.format("sec str pred job \"%s\" finished with status %s",
82 job.getServerJob().getJobId(), status));
83 JPredFile predictionFile = client.getPredictionFile(job.getServerJob());
84 SequenceI[] preds = predictionFile.getSeqsAsArray();
85 Alignment aln = new Alignment(preds);
86 int queryPosition = predictionFile.getQuerySeqPosition();
87 SequenceI profileSeq = aln.getSequenceAt(queryPosition);
88 if (job.delMap != null)
90 SequenceI[] seqs = (SequenceI[]) alignmentView.getAlignmentAndHiddenColumns(gapChar)[0];
91 if (MSA_INDEX >= seqs.length)
92 throw new Error(MessageManager.getString(
93 "error.implementation_error_invalid_msa_index_for_job"));
94 new RemoveGapsCommand(
95 MessageManager.getString("label.remove_gaps"),
96 new SequenceI[] { seqs[MSA_INDEX] }, currentView);
97 profileSeq.setSequence(seqs[MSA_INDEX].getSequenceAsString());
99 if (!SeqsetUtils.SeqCharacterUnhash(aln.getSequenceAt(queryPosition), job.info))
100 throw new IOException(MessageManager.getString("exception.couldnt_recover_sequence_props_for_jnet_query"));
101 aln.setDataset(currentView.getDataset());
104 JnetAnnotationMaker.add_annotation(predictionFile, aln, queryPosition, true,
106 } catch (Exception e)
108 throw new IOException(e);
110 alignToProfileSequence(aln, profileSeq);
111 if (job.delMap != null)
112 aln.setHiddenColumns(aln.propagateInsertions(profileSeq, alignmentView));
114 for (AlignmentAnnotation alnAnnot : aln.getAlignmentAnnotation())
116 if (alnAnnot.sequenceRef != null)
118 AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(alnAnnot,
119 alnAnnot.label, getClass().getSimpleName());
122 aln.setSeqrep(profileSeq);
127 * Given an alignment where all other sequences except profileseq are
128 * aligned to the ungapped profileseq, insert gaps in the other sequences to
129 * realign them with the residues in profileseq.
131 * Shamelessly copied from JPredThread.
136 private static void alignToProfileSequence(AlignmentI al, SequenceI profileseq)
138 char gc = al.getGapCharacter();
139 int[] gapMap = profileseq.gapMap();
140 // insert gaps into profile
141 for (int lp = 0, r = 0; r < gapMap.length; r++)
143 if (gapMap[r] - lp > 1)
145 StringBuffer sb = new StringBuffer();
146 for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
150 for (int s = 1, ns = al.getHeight(); s < ns; s++)
152 String sq = al.getSequenceAt(s).getSequenceAsString();
153 int diff = gapMap[r] - sq.length();
158 while ((diff = gapMap[r] - sq.length()) > 0)
160 sq = sq + ((diff >= sb.length()) ? sb.toString()
161 : sb.substring(0, diff));
163 al.getSequenceAt(s).setSequence(sq);
167 al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r])
168 + sb.toString() + sq.substring(gapMap[r]));
176 public static class SecStructPredJob extends BaseJob
178 private final SequenceInfo info;
180 private final int[] delMap;
182 SecStructPredJob(SequenceI querySequence, int[] delMap,
185 super(List.of(querySequence));
186 this.delMap = delMap;
191 public boolean isInputValid()