Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.ws2.actions.secstructpred

File SecStructPredPDBSearchTask.java

 

Coverage histogram

../../../../img/srcFileCovDistChart7.png
30% of files have more coverage

Code metrics

30
68
6
2
199
172
22
0.32
11.33
3
3.67

Classes

Class Line # Actions
SecStructPredPDBSearchTask 31 64 20
0.663265366.3%
SecStructPredPDBSearchTask.SecStructPredJob 178 4 2
1.0100%
 

Contributing tests

This file is covered by 12 tests. .

Source view

1    package jalview.ws2.actions.secstructpred;
2   
3    import java.io.IOException;
4    import java.util.List;
5   
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;
30   
 
31    public class SecStructPredPDBSearchTask extends
32    BaseTask<SecStructPredPDBSearchTask.SecStructPredJob, AlignmentI>
33    {
34    private final SecStructPredWebServiceClientI client;
35   
36    private final AlignmentView alignmentView;
37    private final AlignmentI currentView;
38    private final char gapChar;
39   
 
40  12 toggle SecStructPredPDBSearchTask(SecStructPredWebServiceClientI client,
41    List<ArgumentI> args, Credentials credentials,
42    AlignViewportI viewport)
43    {
44  12 super(client, args, credentials);
45  12 this.client = client;
46  12 this.alignmentView = viewport.getAlignmentView(true);
47  12 this.currentView = viewport.getAlignment();
48  12 this.gapChar = viewport.getGapCharacter();
49    }
50   
 
51  12 toggle @Override
52    protected List<SecStructPredJob> prepareJobs()
53    throws ServiceInputInvalidException
54    {
55  12 SeqCigar[] msf = alignmentView.getSequences();
56  12 if (msf.length > 1)
57  0 throw new ServiceInputInvalidException(MessageManager.getString(
58    "error.implementation_error_multiple_single_sequence_prediction_jobs_not_supported"));
59  12 SequenceI seq = msf[0].getSeq('-');
60  12 if (seq == null)
61  1 throw new ServiceInputInvalidException("Missing sequence.");
62  11 int[] delMap = alignmentView.getVisibleContigMapFor(seq.gapMap());
63  11 var seqInfo = SeqsetUtils.SeqCharacterHash(seq);
64  11 seq.setSequence(AlignSeq.extractGaps(Comparison.GapChars,
65    alignmentView.getASequenceString('-', 0)));
66  11 if (seq.getLength() < 20)
67  6 throw new ServiceInputInvalidException(
68    "Sequence is too short to predict with JPred - need at least 20 amino acids.");
69  5 var job = new SecStructPredJob(seq, delMap, seqInfo);
70  5 job.setStatus(JobStatus.READY);
71  5 return List.of(job);
72    }
73   
74    public static final int MSA_INDEX = 0;
75   
 
76  1 toggle @Override
77    protected AlignmentI collectResult(List<SecStructPredJob> jobs)
78    throws IOException
79    {
80  1 var job = jobs.get(0); // There should be exactly one job
81  1 var status = job.getStatus();
82  1 Console.info(
83    String.format("sec str pred job \"%s\" finished with status %s",
84    job.getServerJob().getJobId(), status));
85  1 JPredFile predictionFile = client.getPredictionFile(job.getServerJob());
86  1 SequenceI[] preds = predictionFile.getSeqsAsArray();
87  1 Alignment aln = new Alignment(preds);
88  1 int queryPosition = predictionFile.getQuerySeqPosition();
89  1 SequenceI profileSeq = aln.getSequenceAt(queryPosition);
90  1 if (job.delMap != null)
91    {
92  1 SequenceI[] seqs = (SequenceI[]) alignmentView.getAlignmentAndHiddenColumns(gapChar)[0];
93  1 if (MSA_INDEX >= seqs.length)
94  0 throw new Error(MessageManager.getString(
95    "error.implementation_error_invalid_msa_index_for_job"));
96  1 new RemoveGapsCommand(
97    MessageManager.getString("label.remove_gaps"),
98    new SequenceI[] { seqs[MSA_INDEX] }, currentView);
99  1 profileSeq.setSequence(seqs[MSA_INDEX].getSequenceAsString());
100    }
101  1 if (!SeqsetUtils.SeqCharacterUnhash(aln.getSequenceAt(queryPosition), job.info))
102  0 throw new IOException(MessageManager.getString("exception.couldnt_recover_sequence_props_for_jnet_query"));
103  1 aln.setDataset(currentView.getDataset());
104  1 try
105    {
106  1 JnetAnnotationMaker.add_annotation(predictionFile, aln, queryPosition, true,
107    job.delMap);
108    } catch (Exception e)
109    {
110  0 throw new IOException(e);
111    }
112  1 alignToProfileSequence(aln, profileSeq);
113  1 if (job.delMap != null)
114  1 aln.setHiddenColumns(aln.propagateInsertions(profileSeq, alignmentView));
115   
116  1 for (AlignmentAnnotation alnAnnot : aln.getAlignmentAnnotation())
117    {
118  9 if (alnAnnot.sequenceRef != null)
119    {
120  9 AlignmentAnnotationUtils.replaceAnnotationOnAlignmentWith(alnAnnot,
121    alnAnnot.label, getClass().getSimpleName());
122    }
123    }
124  1 aln.setSeqrep(profileSeq);
125  1 return aln;
126    }
127   
128    /**
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.
132    *
133    * Shamelessly copied from JPredThread.
134    *
135    * @param al
136    * @param profileseq
137    */
 
138  1 toggle private static void alignToProfileSequence(AlignmentI al, SequenceI profileseq)
139    {
140  1 char gc = al.getGapCharacter();
141  1 int[] gapMap = profileseq.gapMap();
142    // insert gaps into profile
143  51 for (int lp = 0, r = 0; r < gapMap.length; r++)
144    {
145  50 if (gapMap[r] - lp > 1)
146    {
147  0 StringBuffer sb = new StringBuffer();
148  0 for (int s = 0, ns = gapMap[r] - lp; s < ns; s++)
149    {
150  0 sb.append(gc);
151    }
152  0 for (int s = 1, ns = al.getHeight(); s < ns; s++)
153    {
154  0 String sq = al.getSequenceAt(s).getSequenceAsString();
155  0 int diff = gapMap[r] - sq.length();
156  0 if (diff > 0)
157    {
158    // pad gaps
159  0 sq = sq + sb;
160  0 while ((diff = gapMap[r] - sq.length()) > 0)
161    {
162  0 sq = sq + ((diff >= sb.length()) ? sb.toString()
163    : sb.substring(0, diff));
164    }
165  0 al.getSequenceAt(s).setSequence(sq);
166    }
167    else
168    {
169  0 al.getSequenceAt(s).setSequence(sq.substring(0, gapMap[r])
170    + sb.toString() + sq.substring(gapMap[r]));
171    }
172    }
173    }
174  50 lp = gapMap[r];
175    }
176    }
177   
 
178    public static class SecStructPredJob extends BaseJob
179    {
180    private final SequenceInfo info;
181   
182    private final int[] delMap;
183   
 
184  5 toggle SecStructPredJob(SequenceI querySequence, int[] delMap,
185    SequenceInfo info)
186    {
187  5 super(List.of(querySequence));
188  5 this.delMap = delMap;
189  5 this.info = info;
190    }
191   
 
192  4 toggle @Override
193    public boolean isInputValid()
194    {
195  4 return true;
196    }
197    }
198   
199    }