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();
57 throw new ServiceInputInvalidException(MessageManager.getString(
58 "error.implementation_error_multiple_single_sequence_prediction_jobs_not_supported"));
59 SequenceI seq = msf[0].getSeq('-');
61 throw new ServiceInputInvalidException("Missing sequence.");
62 int[] delMap = alignmentView.getVisibleContigMapFor(seq.gapMap());
63 var seqInfo = SeqsetUtils.SeqCharacterHash(seq);
64 seq.setSequence(AlignSeq.extractGaps(Comparison.GapChars,
65 alignmentView.getASequenceString('-', 0)));
66 if (seq.getLength() < 20)
67 throw new ServiceInputInvalidException(
68 "Sequence is too short to predict with JPred - need at least 20 amino acids.");
69 var job = new SecStructPredJob(seq, delMap, seqInfo);
70 job.setStatus(JobStatus.READY);
74 public static final int MSA_INDEX = 0;
77 protected AlignmentI collectResult(List<SecStructPredJob> jobs)
80 var job = jobs.get(0); // There should be exactly one job
81 var status = job.getStatus();
83 String.format("sec str pred job \"%s\" finished with status %s",
84 job.getServerJob().getJobId(), status));
85 JPredFile predictionFile = client.getPredictionFile(job.getServerJob());
86 SequenceI[] preds = predictionFile.getSeqsAsArray();
87 Alignment aln = new Alignment(preds);
88 int queryPosition = predictionFile.getQuerySeqPosition();
89 SequenceI profileSeq = aln.getSequenceAt(queryPosition);
90 if (job.delMap != null)
92 SequenceI[] seqs = (SequenceI[]) alignmentView.getAlignmentAndHiddenColumns(gapChar)[0];
93 if (MSA_INDEX >= seqs.length)
94 throw new Error(MessageManager.getString(
95 "error.implementation_error_invalid_msa_index_for_job"));
96 new RemoveGapsCommand(
97 MessageManager.getString("label.remove_gaps"),
98 new SequenceI[] { seqs[MSA_INDEX] }, currentView);
99 profileSeq.setSequence(seqs[MSA_INDEX].getSequenceAsString());
101 if (!SeqsetUtils.SeqCharacterUnhash(aln.getSequenceAt(queryPosition), job.info))
102 throw new IOException(MessageManager.getString("exception.couldnt_recover_sequence_props_for_jnet_query"));
103 aln.setDataset(currentView.getDataset());
106 JnetAnnotationMaker.add_annotation(predictionFile, aln, queryPosition, true,
108 } catch (Exception e)
110 throw new IOException(e);
112 alignToProfileSequence(aln, profileSeq);
113 if (job.delMap != null)
114 aln.setHiddenColumns(aln.propagateInsertions(profileSeq, alignmentView));
116 for (AlignmentAnnotation alnAnnot : aln.getAlignmentAnnotation())
118 if (alnAnnot.sequenceRef != null)
120 AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(alnAnnot,
121 alnAnnot.label, getClass().getSimpleName());
124 aln.setSeqrep(profileSeq);
129 * Given an alignment where all other sequences except profileseq are
130 * aligned to the ungapped profileseq, insert gaps in the other sequences to
131 * realign them with the residues in profileseq.
133 * Shamelessly copied from JPredThread.
138 private static void alignToProfileSequence(AlignmentI al, SequenceI profileseq)
140 char gc = al.getGapCharacter();
141 int[] gapMap = profileseq.gapMap();
142 // insert gaps into profile
143 for (int lp = 0, r = 0; r < gapMap.length; r++)
145 if (gapMap[r] - lp > 1)
147 StringBuffer sb = new StringBuffer();
148 for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
152 for (int s = 1, ns = al.getHeight(); s < ns; s++)
154 String sq = al.getSequenceAt(s).getSequenceAsString();
155 int diff = gapMap[r] - sq.length();
160 while ((diff = gapMap[r] - sq.length()) > 0)
162 sq = sq + ((diff >= sb.length()) ? sb.toString()
163 : sb.substring(0, diff));
165 al.getSequenceAt(s).setSequence(sq);
169 al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r])
170 + sb.toString() + sq.substring(gapMap[r]));
178 public static class SecStructPredJob extends BaseJob
180 private final SequenceInfo info;
182 private final int[] delMap;
184 SecStructPredJob(SequenceI querySequence, int[] delMap,
187 super(List.of(querySequence));
188 this.delMap = delMap;
193 public boolean isInputValid()