source: branches/port5/SECEDIT/SEC_read.cxx

Last change on this file was 6068, checked in by westram, 16 years ago
  • fixed some console messages
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : SEC_read.cxx                                      //
4//   Purpose   : read structure from declaration string            //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11
12#include <sstream>
13#include "SEC_root.hxx"
14#include "SEC_iter.hxx"
15
16#define BUFFER_SIZE 1000
17
18using namespace std;
19
20/***********************************************************************
21 * Supplementary Functions
22 ***********************************************************************/
23
24static const char * sec_read_line(istream & in) {
25    static char string_buffer[BUFFER_SIZE];
26    in.getline(string_buffer, BUFFER_SIZE);
27
28    //clean input-stream of whitespaces
29    int j=0;
30    for (int i=0; i<(BUFFER_SIZE-1); i++) {
31        if (!(isspace(string_buffer[i]))) {
32            string_buffer[j] = string_buffer[i];
33            j++;
34            if (string_buffer[i] == '\0') break;
35        }
36    }
37    return string_buffer;
38}
39
40static GB_ERROR sec_scan_ints(const char * string_buffer, int *number_1, int *number_2) {
41    GB_ERROR  error = 0;
42    char     *scanend;          // this is a 'const char *'
43   
44    sec_assert(number_1);
45    *number_1 = (int)strtol(string_buffer, &scanend, 10);
46    if (number_2) {
47        if (scanend[0] != ':') {
48            error = "expected ':' after integer number";
49        }
50        else {
51            *number_2 = (int)strtol(scanend+1, &scanend, 10);
52        }
53    }
54    if (!error && scanend[0] != 0) { // not at string end
55        error = number_2 ? "unexpected content after '=NUMBER:NUMBER'" : "unexpected content after '=NUMBER'";
56    }
57    return error;
58}
59
60static GB_ERROR sec_scan_doubles(const char * string_buffer, double *number_1, double *number_2) {
61    GB_ERROR  error = 0;
62    char     *scanend;          // this is a 'const char *'
63   
64    sec_assert(number_1);
65    *number_1 = strtod(string_buffer, &scanend);
66    if (number_2) {
67        if (scanend[0] != ':') {
68            error = "expected ':' after floating-point number";
69        }
70        else {
71            *number_2 = strtod(scanend+1, &scanend);
72        }
73    }
74    if (!error && scanend[0] != 0) { // not at string end
75        error = number_2 ? "unexpected content after '=NUMBER:NUMBER'" : "unexpected content after '=NUMBER'";
76    }
77    return error;
78}
79
80static GB_ERROR sec_expect_keyword_and_ints(const char *string_buffer, const char *keyword, size_t keywordlen, int *number_1, int *number_2) {
81    // scans 'KEYWORD = NUM:NUM' or 'KEYWORD=NUM'
82    // 1 or 2 numbers are returned via number_1 and number_2
83
84    sec_assert(strlen(keyword) == keywordlen);
85   
86    GB_ERROR error = 0;
87    if (strncmp(string_buffer, keyword, keywordlen) != 0 || string_buffer[keywordlen] != '=') {
88        error = GBS_global_string("Expected '%s='", keyword);
89    }
90    else {
91        error = sec_scan_ints(string_buffer+keywordlen+1, number_1, number_2);
92    }
93    if (error) error = GBS_global_string("%s (while parsing '%s')", error, string_buffer);
94    return error;
95}
96
97static GB_ERROR sec_expect_keyword_and_doubles(const char *string_buffer, const char *keyword, size_t keywordlen, double *number_1, double *number_2) {
98    // scans 'KEYWORD = NUM:NUM' or 'KEYWORD=NUM'
99    // 1 or 2 numbers are returned via number_1 and number_2
100
101    sec_assert(strlen(keyword) == keywordlen);
102   
103    GB_ERROR error = 0;
104    if (strncmp(string_buffer, keyword, keywordlen) != 0 || string_buffer[keywordlen] != '=') {
105        error = GBS_global_string("Expected '%s='", keyword);
106    }
107    else {
108        error = sec_scan_doubles(string_buffer+keywordlen+1, number_1, number_2);
109    }
110    if (error) error = GBS_global_string("%s (while parsing '%s')", error, string_buffer);
111    return error;
112}
113
114static GB_ERROR sec_expect_constraints(const char *string_buffer, const char *keyword, size_t keywordlen, SEC_constrainted *elem) {
115    double   min, max;
116    GB_ERROR error = sec_expect_keyword_and_doubles(string_buffer, keyword, keywordlen, &min, &max);
117    if (!error) elem->setConstraints(min, max);
118    return error;
119}
120
121static GB_ERROR sec_expect_closing_bracket(istream& in) {
122    const char *string_buffer = sec_read_line(in);
123
124    if (strcmp(string_buffer, "}") == 0) return 0;
125    return GBS_global_string("Expected '}' instead of '%s'", string_buffer);
126}
127
128/***********************************************************************
129 * READ-Functions
130 ***********************************************************************/
131
132GB_ERROR SEC_region::read(istream & in, SEC_root *root, int /*version*/) {
133    int         seq_start, seq_end;
134    const char *string_buffer = sec_read_line(in);
135    GB_ERROR    error         = sec_expect_keyword_and_ints(string_buffer, "SEQ", 3, &seq_start, &seq_end);
136
137    if (!error) {
138        sec_assert(root->get_db()->canDisplay());
139        if (root->get_db()->canDisplay()) {
140            const XString& x_string = root->get_xString();
141            int x_count  = x_string.getXcount();
142
143            if (seq_start >= x_count)           error = GBS_global_string("Region start (%i) out of bounds [0..%i]", seq_start, x_count-1);
144            else if (seq_end >= x_count)        error = GBS_global_string("Region end (%i) out of bounds [0..%i]", seq_end, x_count-1);
145            else                                set_sequence_portion(x_string.getAbsPos(seq_start), x_string.getAbsPos(seq_end));
146        }
147        else {
148            set_sequence_portion(seq_start, seq_end);
149        }
150    }
151    return error;
152}
153
154GB_ERROR SEC_segment::read(SEC_loop *loop_, istream & in, int version) {
155    loop              = loop_;
156    GB_ERROR error    = get_region()->read(in, get_root(), version);
157    if (!error) error = sec_expect_closing_bracket(in);
158    return error;
159}
160
161GB_ERROR SEC_helix::read(istream & in, int version, double& old_angle_in) {
162    const char *string_buffer = sec_read_line(in);
163    GB_ERROR    error         = 0;
164
165    old_angle_in = NAN;     // illegal for version >= 3
166
167    if (version >= 3) {
168        double angle;
169
170        error = sec_expect_keyword_and_doubles(string_buffer, "REL", 3, &angle, 0);
171       
172        if (!error) {
173            string_buffer = sec_read_line(in);
174            set_rel_angle(angle);
175        }
176    }
177    else { // version 2 or lower
178        double angle;
179       
180        error = sec_expect_keyword_and_doubles(string_buffer, "DELTA", 5, &angle, 0);
181        if (!error) {
182            string_buffer = sec_read_line(in);
183            set_abs_angle(angle);
184
185            if (version == 2) {
186                error = sec_expect_keyword_and_doubles(string_buffer, "DELTA_IN", 8, &angle, 0);
187
188                if (!error) {
189                    string_buffer = sec_read_line(in);
190                    old_angle_in  = angle+M_PI; // rotate! (DELTA_IN pointed from outside-loop to strand)
191                }
192            }
193            else {
194                old_angle_in = angle; // use strands angle
195            }
196        }
197    }
198
199    if (!error) error = sec_expect_constraints(string_buffer, "LENGTH", 6, this);
200
201    return error;
202}
203
204
205GB_ERROR SEC_helix_strand::read(SEC_loop *loop_, istream & in, int version) {
206    // this points away from root-loop, strand2 points towards root
207
208    SEC_helix_strand *strand2 = new SEC_helix_strand;
209
210    origin_loop = 0; 
211
212    SEC_root *root  = loop_->get_root();
213    GB_ERROR  error = get_region()->read(in, root, version);
214   
215    double next_loop_angle = NAN;
216
217    if (!error) {
218        helix_info  = new SEC_helix(root, strand2, this);
219        origin_loop = loop_;    // needed by read()
220        error       = helix_info->read(in, version, next_loop_angle);
221        origin_loop = 0;
222
223        if (error) {
224            delete helix_info;
225            helix_info          = 0;
226            strand2->helix_info = 0;
227        }
228    }
229
230    if (!error) {
231        const char *string_buffer = sec_read_line(in);
232        if (strncmp(string_buffer, "LOOP={", 6) != 0) {
233            error = GBS_global_string("Strand must be followed by 'LOOP={' (not by '%s')", string_buffer);
234        }
235        else {
236            SEC_loop *new_loop   = new SEC_loop(root);
237            strand2->origin_loop = new_loop;
238
239            error = new_loop->read(strand2, in, version, next_loop_angle);
240
241            if (!error) {
242                error = strand2->get_region()->read(in, root, version); // Loop is complete, now trailing SEQ information must be read
243                string_buffer = sec_read_line(in);    // remove closing } from input-stream
244            }
245           
246            if (error) {
247                strand2->origin_loop = 0;
248                delete new_loop;
249            }
250        }
251    }
252
253    // Note: don't delete strand2 in case of error -- it's done by caller via deleting 'this'
254
255    sec_assert(origin_loop == 0);
256    if (!error) origin_loop = loop_; 
257
258    return error;
259}
260
261
262
263GB_ERROR SEC_loop::read(SEC_helix_strand *rootside_strand, istream & in, int version, double loop_angle) {
264    // loop_angle is only used by old versions<3
265   
266    const char *string_buffer = sec_read_line(in);
267    GB_ERROR    error         = sec_expect_constraints(string_buffer, "RADIUS", 6, this);
268
269    if (!error) {
270        set_fixpoint_strand(rootside_strand);
271
272        if (version == 3) {
273            string_buffer = sec_read_line(in);
274
275            double angle;
276            error = sec_expect_keyword_and_doubles(string_buffer, "REL", 3, &angle, 0);
277            if (!error) set_rel_angle(angle);
278        }
279        else {
280            set_abs_angle(loop_angle);
281            sec_assert(get_rel_angle().valid());
282        }
283    }
284
285    if (!error) {
286        enum { EXPECT_SEGMENT, EXPECT_STRAND } expect = (!rootside_strand && version >= 3) ? EXPECT_STRAND : EXPECT_SEGMENT;
287
288        SEC_segment      *first_new_segment   = 0;
289        SEC_helix_strand *first_new_strand    = 0;
290        SEC_segment      *last_segment        = 0;
291        SEC_helix_strand *last_outside_strand = rootside_strand;
292
293        bool done = false;
294        while (!done && !error) {
295            string_buffer = sec_read_line(in);
296
297            if (strncmp(string_buffer, "}", 1) == 0) {
298                done = true;
299            }
300            else if (expect == EXPECT_SEGMENT) {
301                if (strncmp(string_buffer, "SEGMENT={", 9) == 0) {
302                    SEC_segment *new_seg = new SEC_segment;
303
304                    error = new_seg->read(this, in, version);
305                    if (!error) {
306                        if (last_outside_strand) last_outside_strand->set_next_segment(new_seg);
307                        last_outside_strand = 0;
308                        last_segment        = new_seg;
309
310                        if (!first_new_segment) first_new_segment = new_seg;
311                       
312                        expect = EXPECT_STRAND;
313                    }
314                    else delete new_seg;
315                }
316                else error = GBS_global_string("Expected SEGMENT (in '%s')", string_buffer);
317            }
318            else {
319                sec_assert(expect == EXPECT_STRAND);
320                if (strncmp(string_buffer, "STRAND={", 8) == 0) {
321                    SEC_helix_strand *new_strand = new SEC_helix_strand;
322
323                    error = new_strand->read(this, in, version);
324                    if (!error) {
325                        if (last_segment) last_segment->set_next_strand(new_strand);
326                        last_outside_strand = new_strand;
327                        last_segment        = 0;
328
329                        if (!first_new_strand) {
330                            first_new_strand = new_strand;
331                            if (!rootside_strand) set_fixpoint_strand(first_new_strand);
332                        }
333
334                        expect = EXPECT_SEGMENT;
335                    }
336                    else delete new_strand;
337                }
338                else error = GBS_global_string("Expected STRAND (in '%s')", string_buffer);
339            }
340        }
341       
342        if (!error && !first_new_segment) error = "Expected at least one SEGMENT in LOOP{}";
343        if (!error && !first_new_strand && !rootside_strand) error = "Expected at least one STRAND in root-LOOP{}";
344
345        if (!error) {
346            if (last_segment) {
347                sec_assert(last_segment->get_next_strand() == 0);
348                if (rootside_strand) {
349                    last_segment->set_next_strand(rootside_strand);
350                }
351                else { // root loop (since version 3)
352                    last_segment->set_next_strand(first_new_strand);
353                }
354            }
355            else {
356                sec_assert(last_outside_strand);
357                sec_assert(version<3); // version 3 loops always end with segment
358
359                sec_assert(!rootside_strand); // only occurs in root-loop
360                last_outside_strand->set_next_segment(first_new_segment);
361               
362            }
363        }
364        else {
365            if (rootside_strand) rootside_strand->set_next_segment(0); // unlink me from parent
366        }
367    }
368
369    if (error) set_fixpoint_strand(0);
370
371    return error;
372}
373
374GB_ERROR SEC_root::read_data(const char *input_string, const char *x_string_in) {
375    istringstream in(input_string);
376
377    delete xString;
378    xString = 0;
379
380    GB_ERROR error   = 0;
381    int      version = -1;      // version of structure string
382
383    sec_assert(db->canDisplay());
384
385    if (!error) {
386        const char *string_buffer  = sec_read_line(in);
387        double      firstLoopAngle = 0; 
388
389        error = sec_expect_keyword_and_ints(string_buffer, "VERSION", 7, &version, 0); // version 3++
390        if (error) { // version < 3!
391            version = 2;        // or less
392
393            int ignoreMaxIndex;
394            error = sec_expect_keyword_and_ints(string_buffer, "MAX_INDEX", 9, &ignoreMaxIndex, 0); // version 1+2
395            if (!error) {
396                string_buffer = sec_read_line(in);
397                error = sec_expect_keyword_and_doubles(string_buffer, "ROOT_ANGLE", 10, &firstLoopAngle, 0); // version 2 only
398                if (error) {
399                    firstLoopAngle += M_PI;
400                    version = 1; // version 1 had no ROOT_ANGLE entry
401                    error   = 0;
402                }
403                else {
404                    firstLoopAngle += M_PI;
405                    string_buffer = sec_read_line(in);
406                }
407            }
408        }
409        else {
410            if (version>DATA_VERSION) {
411                error = GBS_global_string("Structure has version %i, your ARB can only handle versions up to %i", version, DATA_VERSION);
412            }
413            else {
414                string_buffer = sec_read_line(in);
415            }
416        }
417
418        if (!error) { //   && db->canDisplay()
419            sec_assert(!xString);
420
421            size_t len     = strlen(x_string_in);
422            size_t exp_len = db->length();
423
424            if (len != exp_len && len != (exp_len+1)) {
425                error = GBS_global_string("Wrong xstring-length (found=%zu, expected=%zu-%zu)",
426                                          len, exp_len, exp_len+1);
427            }
428            else {
429                xString = new XString(x_string_in, len, db->length());
430#if defined(DEBUG)
431                size_t xlen = xString->getLength(); // internally one position longer than alignment length
432                printf("x_string_in len=%zu\nxlen=%zu\nali_length=%zu\n", strlen(x_string_in), xlen, db->length());
433#endif // DEBUG
434            }
435        }
436
437        delete_root_loop();
438   
439        if (!error) {
440#if defined(DEBUG)
441            printf("Reading structure format (version %i)\n", version);
442#endif // DEBUG
443
444            if (strncmp(string_buffer, "LOOP={", 6) == 0) {
445                SEC_loop *rootLoop = new SEC_loop(this); // , NULL, 0, 0);
446
447                set_root_loop(rootLoop);
448                set_under_construction(true);
449                error = rootLoop->read(NULL, in, version, firstLoopAngle);
450
451                if (!error) {
452                    set_under_construction(false); // mark as "constructed"
453                }
454                else {
455                    delete_root_loop();
456                }
457            }
458            else {
459                error = GBS_global_string("Expected root loop ('LOOP={'), not '%s'", string_buffer);
460            }
461        }
462    }
463
464    if (!error) {
465        if (version<DATA_VERSION) {
466            printf("Converting secondary structure from version %i to %i\n", version, DATA_VERSION);
467        }
468        if (version<3) fixStructureBugs(version);
469#if defined(CHECK_INTEGRITY)
470        check_integrity(CHECK_STRUCTURE);
471#endif // CHECK_INTEGRITY
472        if (version<3) {
473            relayout();
474            root_loop->fixAngleBugs(version);
475        }
476    }
477
478    return error;
479}
480
481void SEC_helix::fixAngleBugs(int version) {
482    if (version<3) {
483        outsideLoop()->fixAngleBugs(version); // first correct substructure
484
485        // versions<3 silently mirrored angles between strand and origin-loop
486        // to ensure that strand always points away from loop (and not inside).
487        // This correction was done during refresh and therefore not saved to the DB.
488        // Since version 3 no angles will be mirrored automatically, so we need to correct them here.
489
490        Vector loop2strand(rootsideLoop()->get_center(), get_fixpoint());
491        if (scalarProduct(loop2strand, get_abs_angle().normal()) < 0) { // < 0 means angle is an acute angle
492            printf("* Autofix acute angle (loop2strand=%.2f, abs=%.2f) of helix nr '%s'\n",
493                   Angle(loop2strand).radian(),
494                   get_abs_angle().radian(),
495                   get_root()->helixNrAt(strandToOutside()->startAttachAbspos()));
496            set_rel_angle(Angle(get_rel_angle()).rotate180deg());
497        }
498    }
499}
500
501void SEC_loop::fixAngleBugs(int version) {
502    if (version<3) {
503        for (SEC_strand_iterator strand(this); strand; ++strand) {
504            if (strand->pointsToOutside()) {
505                strand->get_helix()->fixAngleBugs(version);
506            }
507        }
508    }
509}
510
511void SEC_root::fixStructureBugs(int version) {
512    if (version < 3) {
513        // old versions produced data structure with non-adjacent regions
514        SEC_base_part *start_part = root_loop->get_fixpoint_strand();
515        SEC_base_part *part       = start_part;
516        SEC_region    *reg        = part->get_region();
517
518        do {
519            SEC_base_part *next_part = part->next();
520            SEC_region    *next_reg  = next_part->get_region();
521
522            if (!are_adjacent_regions(reg, next_reg)) {
523                printf("* Fixing non-adjacent regions: %i..%i and %i..%i\n",
524                       reg->get_sequence_start(), reg->get_sequence_end(),
525                       next_reg->get_sequence_start(), next_reg->get_sequence_end());
526
527                // known bug occurs at segment->strand transition..
528                sec_assert(part->parent()->getType() == SEC_LOOP);
529
530                // .. and segment region ends one position too early
531                sec_assert(get_helixDef()->helixNr(reg->get_sequence_end()) == 0);
532                sec_assert(get_helixDef()->helixNr(next_reg->get_sequence_start()) != 0);
533
534                // make them adjacent
535                reg->set_sequence_portion(reg->get_sequence_start(), next_reg->get_sequence_start());
536            }
537
538            part = next_part;
539            reg  = next_reg;
540        }
541        while (part != start_part);
542    }
543}
Note: See TracBrowser for help on using the repository browser.