source: tags/arb_5.0/TOOLS/arb_gene_probe.cxx

Last change on this file was 5894, checked in by westram, 15 years ago
  • reactivated original GB_close
  • removed GB_exit (use GB_close)
  • gb_delete_entry now takes and invalidates a GBDATA (to avoid further undetected usage)
  • gb_do_callback_list called with GB_MAIN_TYPE (instead of possibly already deleted gb_main)
  • added some missing transactions
  • moved declaration of GBDATA into arbdb_base.h (and include where needed)
  • GB_MAIN_TYPE is no longer void
  • AW_default is no longer void
  • replaced the 3 differing ways to exit EDIT4 by ED4_exit()
  • added AW_root::unlink_awars_from_DB() and call in arb_ntree, arb_dist, arb_edit4, arb_pars and arb_phylo
  • rewrote arb_2_ascii, arb_2_bin, arb_perf_test, arb_read_tree (single exit point, error handling)
  • unlinked AWARs now return "" not "?????"
  • AW_awar::read_string works only with awars of type AW_STRING. Added assertion + fixed one wrong usage.
  • inlined AW_awar::get()
  • added AW_awar::remove_all_callbacks() and AW_awar::remove_all_target_vars()
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1#include <arbdb.h>
2#include <arbdbt.h>
3#include <adGene.h>
4
5#include <map>
6#include <list>
7#include <set>
8
9#include <cstdio>
10#include <cstdlib>
11#include <cstring>
12
13#include <unistd.h>
14#include <sys/types.h>
15
16#define gp_assert(cond) arb_assert(cond)
17
18using namespace std;
19
20#if defined(DEBUG)
21// #define CREATE_DEBUG_FILES
22// #define DUMP_OVERLAP_CALC
23#endif // DEBUG
24
25// --------------------------------------------------------------------------------
26
27static int gene_counter          = 0; // pre-incremented counters
28static int splitted_gene_counter = 0;
29static int intergene_counter     = 0;
30
31static map<const char *,char *> names;
32
33// --------------------------------------------------------------------------------
34
35struct PositionPair {
36    int begin;                  // these positions are in range [0 .. genome_length-1]
37    int end;
38
39    static int genome_length;
40
41#if defined(DEBUG)
42    void check_legal() const {
43        gp_assert(begin >= 0);
44        gp_assert(begin <= end);
45        gp_assert(end < genome_length);
46    }
47#endif // DEBUG
48
49    PositionPair() : begin(-1), end(-1) {}
50    PositionPair(int begin_, int end_) : begin(begin_), end(end_) {
51#if defined(DEBUG)
52        check_legal();
53#endif // DEBUG
54    }
55
56    int length() const { return end-begin+1; }
57
58    bool overlapsWith(const PositionPair& other) const {
59#if defined(DEBUG)
60        check_legal();
61        other.check_legal();
62#endif // DEBUG
63        return ! ((end < other.begin) || (other.end < begin));
64    }
65
66#if defined(DUMP_OVERLAP_CALC)
67    void dump(const char *note) const {
68        printf("%s begin=%i end=%i\n", note, begin, end);
69    }
70#endif // DUMP_OVERLAP_CALC
71};
72
73int PositionPair::genome_length = 0;
74
75typedef list<PositionPair> PositionPairList;
76
77struct ltNonOverlap {
78    // sorting with this operator identifies all overlapping PositionPair's as "equal"
79    bool operator ()(const PositionPair& p1, const PositionPair& p2) const {
80        return p1.end < p2.begin;
81    }
82};
83
84class GenePositionMap {
85    typedef set<PositionPair, ltNonOverlap> OverlappingGeneSet;
86
87    OverlappingGeneSet usedRanges;
88    unsigned long      overlapSize;
89    unsigned long      geneSize;
90public:
91    GenePositionMap() : overlapSize(0), geneSize(0) {}
92
93    void announceGene(PositionPair gene);
94    GB_ERROR buildIntergeneList(const PositionPair& wholeGenome, PositionPairList& intergeneList) const;
95    unsigned long getOverlap() const { return overlapSize; }
96    unsigned long getAllGeneSize() const { return geneSize; }
97
98#if defined(DUMP_OVERLAP_CALC)
99    void dump() const;
100#endif // DUMP_OVERLAP_CALC
101};
102
103// ____________________________________________________________
104// start of implementation of class GenePositionMap:
105
106void GenePositionMap::announceGene(PositionPair gene)
107{
108    OverlappingGeneSet::iterator found = usedRanges.find(gene);
109    if (found == usedRanges.end()) { // gene does not overlap with currently known ranges
110        usedRanges.insert(gene); // add to known ranges
111    }
112    else {
113        // 'found' overlaps with 'gene'
114        int gene_length = gene.length();
115
116        do {
117            gp_assert(gene.overlapsWith(*found));
118
119            gene                = PositionPair(min(found->begin, gene.begin), max(found->end, gene.end)); // calc combined range
120            int combined_length = gene.length();
121
122            size_t overlap  = (found->length()+gene_length)-combined_length;
123            overlapSize    += overlap;
124            geneSize       += gene_length;
125
126            usedRanges.erase(found);
127
128            gene_length = combined_length;
129            found       = usedRanges.find(gene); // search for further overlaps
130        } while (found != usedRanges.end());
131
132        usedRanges.insert(gene); // insert the combined range
133    }
134}
135
136GB_ERROR GenePositionMap::buildIntergeneList(const PositionPair& wholeGenome, PositionPairList& intergeneList) const
137{
138    OverlappingGeneSet::iterator end  = usedRanges.end();
139    OverlappingGeneSet::iterator curr = usedRanges.begin();
140    OverlappingGeneSet::iterator prev = end;
141
142    if (curr == end) { // nothing defined -> use whole genome as one big intergene
143        intergeneList.push_back(wholeGenome);
144    }
145    else {
146        if (curr->begin > wholeGenome.begin) { // intergene before first gene range ?
147            intergeneList.push_back(PositionPair(wholeGenome.begin, curr->begin-1));
148        }
149
150        prev = curr; ++curr;
151
152        while (curr != end) {
153            if (prev->end < curr->begin) {
154                if (prev->end != (curr->begin-1)) { // not directly adjacent
155                    intergeneList.push_back(PositionPair(prev->end+1, curr->begin-1));
156                }
157            }
158            else {
159                return "Internal error: Overlapping gene ranges";
160            }
161
162            prev = curr; ++curr;
163        }
164
165        if (prev != end && prev->end < wholeGenome.end) {
166            intergeneList.push_back(PositionPair(prev->end+1, wholeGenome.end));
167        }
168    }
169    return 0;
170}
171
172#if defined(DUMP_OVERLAP_CALC)
173void GenePositionMap::dump() const
174{
175    printf("List of ranges used by genes:\n");
176    for (OverlappingGeneSet::iterator g = usedRanges.begin(); g != usedRanges.end(); ++g) {
177        g->dump("- ");
178    }
179    printf("Overlap: %lu bases\n", getOverlap());
180}
181#endif // DUMP_OVERLAP_CALC
182
183// -end- of implementation of class GenePositionMap.
184
185static GB_ERROR create_data_entry(GBDATA *gb_species2, const char *sequence, int seqlen) {
186    GB_ERROR  error         = 0;
187    char     *gene_sequence = new char[seqlen+1];
188   
189    memcpy(gene_sequence, sequence, seqlen);        // @@@ FIXME: avoid this copy!
190    gene_sequence[seqlen] = 0;
191
192    GBDATA *gb_ali     = GB_create_container(gb_species2, "ali_ptgene");
193    if (!gb_ali) error = GB_await_error();
194    else    error      = GBT_write_string(gb_ali, "data", gene_sequence);
195   
196    delete [] gene_sequence;
197    return error;
198}
199
200#if defined(DEBUG)
201void CHECK_SEMI_ESCAPED(const char *name) {
202    // checks whether all ";\\" are escaped
203    while (*name) {
204        gp_assert(*name != ';'); // oops, unescaped ';'
205        if (*name == '\\') ++name;
206        ++name;
207    }
208}
209#else
210#define CHECK_SEMI_ESCAPED(s)
211#endif // DEBUG
212
213
214static GBDATA *create_gene_species(GBDATA *gb_species_data2, const char *internal_name, const char *long_name, int abspos, const char *sequence, int length) {
215    // Note: 'sequence' is not necessarily 0-terminated!
216
217#if defined(DEBUG)
218    char *firstSem = strchr(long_name, ';');
219    gp_assert(firstSem);
220    CHECK_SEMI_ESCAPED(firstSem+1);
221#endif // DEBUG
222
223    GB_ERROR  error       = GB_push_transaction(gb_species_data2);
224    GBDATA   *gb_species2 = 0;
225
226    if (!error) {
227        gb_species2 = GB_create_container(gb_species_data2, "species");
228        if (!gb_species2) error = GB_await_error();
229    }
230
231    if (!error) {
232        GBDATA *gb_name = GB_create(gb_species2, "name", GB_STRING);
233       
234        if (!gb_name) error = GB_await_error();
235        else {
236            error = GB_write_string(gb_name, internal_name);
237            if (!error) {
238                const char *static_internal_name = GB_read_char_pntr(gb_name); // use static copy from db as map-index (internal_name is temporary)
239                error                            = create_data_entry(gb_species2, sequence, length);
240                if (!error) {
241                    names[static_internal_name] = strdup(long_name);
242                    error = GBT_write_int(gb_species2, "abspos", abspos);
243#if defined(DEBUG)
244                    // store realname for debugging purposes
245                    if (!error) error = GBT_write_string(gb_species2, "realname_debug", long_name);
246#endif // DEBUG
247                }
248            }
249        }
250    }
251
252    error = GB_end_transaction(gb_species_data2, error);
253
254    if (error) { // be more verbose :
255        error       = GBS_global_string("%s (internal_name='%s', long_name='%s')", error, internal_name, long_name);
256        GB_export_error(error);
257        gb_species2 = NULL;
258    }
259
260    return gb_species2;
261}
262
263static GB_ERROR create_genelike_entry(const char *internal_name, GBDATA *gb_species_data2, int start_pos, int end_pos, const char *ali_genome, const char *long_name) {
264    GBDATA *gb_genespecies = create_gene_species(gb_species_data2, internal_name, long_name, start_pos, ali_genome+start_pos, end_pos-start_pos+1);
265    return gb_genespecies ? 0 : GB_await_error();
266}
267
268static GB_ERROR create_intergene(GBDATA *gb_species_data2, int start_pos, int end_pos, const char *ali_genome, const char *long_gene_name) {
269    if (start_pos <= end_pos) {
270        char internal_name[128];
271        sprintf(internal_name, "i%x", intergene_counter++);
272        return create_genelike_entry(internal_name, gb_species_data2, start_pos, end_pos, ali_genome, long_gene_name);
273    }
274    return "Illegal inter-gene positions (start behind end)";
275}
276
277static GB_ERROR create_gene(GBDATA *gb_species_data2, int start_pos, int end_pos, const char *ali_genome, const char *long_gene_name) {
278    if (start_pos <= end_pos) {
279        char internal_name[128];
280        sprintf(internal_name, "n%x", gene_counter++);
281        return create_genelike_entry(internal_name, gb_species_data2, start_pos, end_pos, ali_genome, long_gene_name);
282    }
283    return "Illegal gene positions (start behind end)";
284}
285
286static GB_ERROR create_splitted_gene(GBDATA *gb_species_data2, PositionPairList& part_list, const char *ali_genome, const char *long_gene_name) {
287    GB_ERROR                     error    = 0;
288    PositionPairList::iterator list_end = part_list.end();
289
290    int gene_size = 0;
291    for (PositionPairList::iterator part = part_list.begin(); part != list_end; ++part) {
292        int part_size  = part->end-part->begin+1;
293        gp_assert(part_size > 0);
294        gene_size     += part_size;
295    }
296    gp_assert(gene_size > 0);
297    char *gene_sequence = new char[gene_size+1];
298    int   gene_off      = 0;
299
300    char *split_pos_list = 0;   // contains split information: 'gene pos of part2,abs pos of part2;gene pos of part3,abs pos of part3;...'
301
302    for (PositionPairList::iterator part = part_list.begin(); part != list_end; ) {
303        int part_size   = part->end-part->begin+1;
304        int genome_pos  = part->begin;
305        memcpy(gene_sequence+gene_off, ali_genome+part->begin, part_size);
306        gene_off       += part_size;
307
308        ++part;
309
310        if (split_pos_list == 0) { // first part
311            split_pos_list = GBS_global_string_copy("%i", gene_off); // gene offset of part 2
312        }
313        else {                  // next parts
314            char *next_split_pos_list;
315            if (part != list_end) { // not last
316                next_split_pos_list = GBS_global_string_copy("%s,%i;%i", split_pos_list, genome_pos, gene_off);
317            }
318            else { // last part
319                next_split_pos_list = GBS_global_string_copy("%s,%i", split_pos_list, genome_pos);
320            }
321            freeset(split_pos_list, next_split_pos_list);
322        }
323    }
324
325    char internal_name[128];
326    sprintf(internal_name, "s%x", splitted_gene_counter++);
327
328    const PositionPair&  first_part  = part_list.front();
329    GBDATA              *gb_species2 = create_gene_species(gb_species_data2, internal_name, long_gene_name, first_part.begin,
330                                                           gene_sequence, first_part.end-first_part.begin+1);
331
332    if (!gb_species2) error = GB_await_error();
333    else {
334#if defined(DEBUG) && 0
335        printf("splitted gene: long_gene_name='%s' internal_name='%s' split_pos_list='%s'\n",
336               long_gene_name, internal_name, split_pos_list);
337#endif // DEBUG
338        error = GBT_write_string(gb_species2, "splitpos", split_pos_list);
339    }
340
341    free(split_pos_list);
342    delete [] gene_sequence;
343
344    return error;
345}
346
347static GB_ERROR scan_gene_positions(GBDATA *gb_gene, PositionPairList& part_list) {
348    GB_ERROR      error    = 0;
349    GEN_position *location = GEN_read_position(gb_gene);
350
351    if (!location) error = GB_await_error();
352    else {
353        GEN_sortAndMergeLocationParts(location);
354        int parts = location->parts;
355        for (int p = 0; p<parts; ++p) {
356            part_list.push_back(PositionPair(location->start_pos[p]-1, location->stop_pos[p]-1));
357        }
358        GEN_free_position(location);
359    }
360    return error;
361}
362
363static GB_ERROR insert_genes_of_organism(GBDATA *gb_organism, GBDATA *gb_species_data2) {
364    // insert all genes of 'gb_organism' as pseudo-species
365    // into new 'species_data' (gb_species_data2)
366
367    GB_ERROR    error            = 0;
368    const char *organism_name = GBT_read_name(gb_organism);
369
370    GenePositionMap geneRanges;
371
372    int gene_counter_old          = gene_counter; // used for statistics only (see end of function)
373    int splitted_gene_counter_old = splitted_gene_counter;
374    int intergene_counter_old     = intergene_counter;
375
376    GBDATA *gb_ali_genom = GBT_read_sequence(gb_organism, GENOM_ALIGNMENT);
377    gp_assert(gb_ali_genom);                                                       // existance has to be checked by caller!
378   
379    const char *ali_genom       = GB_read_char_pntr(gb_ali_genom);
380    if (!ali_genom) error       = GB_await_error();
381    PositionPair::genome_length = GB_read_count(gb_ali_genom);     // this affects checks in PositionPair
382
383    for (GBDATA *gb_gene = GEN_first_gene(gb_organism);
384         gb_gene && !error;
385         gb_gene = GEN_next_gene(gb_gene))
386    {
387        const char *gene_name = GBT_read_name(gb_gene);
388       
389        PositionPairList part_list;
390        error = scan_gene_positions(gb_gene, part_list);
391
392        if (!error && part_list.empty()) error = "empty position list";
393        if (!error) {
394            int          split_count = part_list.size();
395            PositionPair first_part  = *part_list.begin();
396
397            if (!error) {
398                char *esc_gene_name = GBS_escape_string(gene_name, ";", '\\');
399                char *long_gene_name = GBS_global_string_copy("%s;%s", organism_name, esc_gene_name);
400                if (split_count == 1) { // normal gene
401                    error = create_gene(gb_species_data2, first_part.begin, first_part.end, ali_genom, long_gene_name);
402                    geneRanges.announceGene(first_part);
403                }
404                else {          // splitted gene
405                    error = create_splitted_gene(gb_species_data2, part_list, ali_genom, long_gene_name);
406
407                    for (PositionPairList::iterator p = part_list.begin(); p != part_list.end(); ++p) {
408                        geneRanges.announceGene(*p);
409                    }
410                }
411                free(long_gene_name);
412                free(esc_gene_name);
413            }
414        }
415
416        if (error && gene_name) error = GBS_global_string("in gene '%s': %s", gene_name, error);
417    }
418
419    if (!error) { // add intergenes
420        PositionPairList intergenes;
421        PositionPair     wholeGenome(0, PositionPair::genome_length-1);
422        error = geneRanges.buildIntergeneList(wholeGenome, intergenes);
423
424        for (PositionPairList::iterator i = intergenes.begin(); !error && i != intergenes.end(); ++i) {
425            char *long_intergene_name = GBS_global_string_copy("%s;intergene_%i_%i", organism_name, i->begin, i->end);
426            error                     = create_intergene(gb_species_data2, i->begin, i->end, ali_genom, long_intergene_name);
427            free(long_intergene_name);
428        }
429    }
430
431    if (error && organism_name) error = GBS_global_string("in organism '%s': %s", organism_name, error);
432
433    {
434        int new_genes          = gene_counter-gene_counter_old; // only non-splitted genes
435        int new_splitted_genes = splitted_gene_counter-splitted_gene_counter_old;
436        int new_intergenes     = intergene_counter-intergene_counter_old;
437
438        unsigned long genesSize    = geneRanges.getAllGeneSize();
439        unsigned long overlaps     = geneRanges.getOverlap();
440        double        data_grow    = overlaps/double(PositionPair::genome_length)*100;
441        double        gene_overlap = overlaps/double(genesSize)*100;
442
443        if (new_splitted_genes) {
444
445            printf("  - %s: %u genes (%u splitted), %u intergenes",
446                   organism_name, new_genes+new_splitted_genes, new_splitted_genes, new_intergenes);
447        }
448        else {
449            printf("  - %s: %u genes, %u intergenes",
450                   organism_name, new_genes, new_intergenes);
451        }
452        printf(" (data grow: %5.2f%%, gene overlap: %5.2f%%=%lu bp)\n", data_grow, gene_overlap, overlaps);
453    }
454
455#if defined(DUMP_OVERLAP_CALC)
456    geneRanges.dump();
457#endif // DUMP_OVERLAP_CALC
458
459    return error;
460}
461
462int main(int argc, char* argv[]) {
463
464    printf("\n"
465           "arb_gene_probe 1.2 -- (C) 2003/2004 Lehrstuhl fuer Mikrobiologie - TU Muenchen\n"
466           "written by Tom Littschwager, Bernd Spanfelner, Conny Wolf, Ralf Westram.\n");
467
468    if (argc != 3) {
469        printf("Usage: arb_gene_probe input_database output_database\n");
470        printf("       Prepares a genome database for Gene-PT-Server\n");
471        return EXIT_FAILURE;
472    }
473
474    const char *inputname  = argv[1];
475    const char *outputname = argv[2];
476
477    printf("Converting '%s' -> '%s' ..\n", inputname, outputname);
478
479    GB_ERROR  error   = 0;
480    GBDATA   *gb_main = GB_open(inputname, "rw"); // rootzeiger wird gesetzt
481    if (!gb_main) {
482        error = GBS_global_string("Database '%s' not found", inputname);
483    }
484    else {
485        GB_request_undo_type(gb_main, GB_UNDO_NONE); // disable arbdb builtin undo
486        GB_begin_transaction(gb_main);
487
488        GBDATA *gb_species_data     = GB_entry(gb_main,"species_data");
489        GBDATA *gb_species_data_new = GB_create_container(gb_main,"species_data"); // introducing a second 'species_data' container
490
491        if (!gb_species_data || ! gb_species_data_new) {
492            error = GB_await_error();
493        }
494
495        int non_ali_genom_species = 0;
496        int ali_genom_species     = 0;
497
498        for (GBDATA *gb_species = GBT_first_species_rel_species_data(gb_species_data);
499             gb_species && !error;
500             gb_species = GBT_next_species(gb_species))
501        {
502            GBDATA *gb_ali_genom = GBT_read_sequence(gb_species, GENOM_ALIGNMENT);
503            if (!gb_ali_genom) {
504                // skip species w/o alignment 'GENOM_ALIGNMENT' (genome DBs often contain pseudo species)
505                ++non_ali_genom_species;
506            }
507            else {
508                error = insert_genes_of_organism(gb_species, gb_species_data_new);
509                ++ali_genom_species;
510            }
511        }
512
513        if (non_ali_genom_species) {
514            printf("%i species had no alignment in '" GENOM_ALIGNMENT "' and have been skipped.\n", non_ali_genom_species);
515        }
516        if (ali_genom_species == 0) {
517            error = "no species with data in alignment '" GENOM_ALIGNMENT "' were found";
518        }
519
520        if (!error) {
521            printf("%i species had data in alignment '" GENOM_ALIGNMENT "'.\n"
522                   "Found %i genes (%i were splitted) and %i intergene regions.\n",
523                   ali_genom_species, gene_counter, splitted_gene_counter, intergene_counter);
524        }
525
526        if (!error) {
527            error = GB_delete(gb_species_data); // delete first (old) 'species_data' container
528        }
529
530        if (!error) {
531            // create map-string
532            char* map_string;
533            {
534                map<const char*,char*>::iterator NameEnd = names.end();
535                map<const char*,char*>::iterator NameIter;
536
537                size_t mapsize = 0;
538                for (NameIter = names.begin(); NameIter != NameEnd; ++NameIter) {
539                    mapsize += strlen(NameIter->first)+strlen(NameIter->second)+2;
540                }
541
542                map_string  = new char[mapsize+1];
543                size_t moff = 0;
544
545                for (NameIter = names.begin(); NameIter != NameEnd; ++NameIter) {
546                    int len1 = strlen(NameIter->first);
547                    int len2 = strlen(NameIter->second);
548
549                    memcpy(map_string+moff, NameIter->first, len1);
550                    map_string[moff+len1]  = ';';
551                    moff                  += len1+1;
552
553                    memcpy(map_string+moff, NameIter->second, len2);
554                    map_string[moff+len2]  = ';';
555                    moff                  += len2+1;
556                }
557                map_string[moff] = 0;
558
559                gp_assert(moff <= mapsize);
560            }
561
562            GBDATA *gb_gene_map     = GB_create_container(gb_main,"gene_map");
563            if (!gb_gene_map) error = GB_await_error();
564            else    error           = GBT_write_string(gb_gene_map, "map_string", map_string);
565        }
566
567        if (!error) {
568            // set default alignment for pt_server
569            error = GBT_set_default_alignment(gb_main, "ali_ptgene");
570
571            if (!error) {
572                GBDATA *gb_use     = GB_search(gb_main,"presets/alignment/alignment_name",GB_STRING);
573                if (!gb_use) error = GB_await_error();
574                else {
575                    GB_push_my_security(gb_main);
576                    error = GB_write_string(gb_use,"ali_ptgene");
577                    GB_pop_my_security(gb_main);
578                }
579            }
580        }
581
582        error = GB_end_transaction(gb_main, error);
583
584        if (!error) {
585            printf("Saving '%s' ..\n", outputname);
586            error = GB_save_as(gb_main, outputname, "bfm");
587            if (error) unlink(outputname);
588        }
589
590        GB_close(gb_main);
591    }
592
593    if (error) {
594        printf("Error in arb_gene_probe: %s\n", error);
595        return EXIT_FAILURE;
596    }
597
598    printf("arb_gene_probe done.\n");
599    return EXIT_SUCCESS;
600}
601
Note: See TracBrowser for help on using the repository browser.