source: tags/arb_5.1/MERGE/MG_preserves.cxx

Last change on this file was 6100, checked in by westram, 15 years ago
  • fix warning "format not a string literal and no format arguments"
    • GB_export_error → GB_export_error/GB_export_errorf
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1//  ==================================================================== //
2//                                                                       //
3//    File      : MG_preserves.cxx                                       //
4//    Purpose   : find candidates for alignment preservation             //
5//                                                                       //
6//                                                                       //
7//  Coded by Ralf Westram (coder@reallysoft.de) in July 2003             //
8//  Copyright Department of Microbiology (Technical University Munich)   //
9//                                                                       //
10//  Visit our web site at: http://www.arb-home.de/                       //
11//                                                                       //
12//                                                                       //
13//  ==================================================================== //
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <arbdb.h>
19#include <arbdbt.h>
20#include <aw_root.hxx>
21#include <aw_device.hxx>
22#include <aw_window.hxx>
23#include <aw_awars.hxx>
24#include <awt.hxx>
25#include "merge.hxx"
26
27#include <set>
28#include <string>
29#include <smartptr.h>
30#include <cassert>
31
32using namespace std;
33
34// find species/SAIs to preserve alignment
35
36#define AWAR_REMAP_CANDIDATE    "tmp/merge/remap_candidates"
37#define AWAR_REMAP_ALIGNMENT    "tmp/merge/remap_alignment"
38
39struct preserve_para {
40    AW_window         *window;
41    AW_selection_list *ali_id;
42    AW_selection_list *cand_id;
43};
44
45// get all alignment names available in both databases
46static char **get_global_alignments() {
47    char   **src_ali_names = GBT_get_alignment_names(GLOBAL_gb_merge);
48    GBDATA  *gb_presets    = GB_search(GLOBAL_gb_dest, "presets", GB_CREATE_CONTAINER);
49    int      i;
50
51    for (i = 0; src_ali_names[i]; ++i) {
52        GBDATA *gb_ali_name = GB_find_string(gb_presets, "alignment_name", src_ali_names[i], GB_IGNORE_CASE, down_2_level);
53        if (!gb_ali_name) freeset(src_ali_names[i], 0);
54    }
55
56    int k = 0;
57    for (int j = 0; j<i; ++j) {
58        if (src_ali_names[j]) {
59            if (j != k) {
60                src_ali_names[k] = src_ali_names[j];
61                src_ali_names[j] = 0;
62            }
63            ++k;
64        }
65    }
66
67    return src_ali_names;
68}
69
70// initialize the alignment selection list
71static void init_alignments(preserve_para *para) {
72    AW_window         *aww = para->window;
73    AW_selection_list *id  = para->ali_id;
74
75    aww->clear_selection_list(id);
76    aww->insert_default_selection(id, "All", "All");
77
78    // insert alignments available in both databases
79    char **ali_names = get_global_alignments();
80    for (int i = 0; ali_names[i]; ++i) {
81        aww->insert_selection(id, ali_names[i], ali_names[i]);
82    }
83    GBT_free_names(ali_names);
84
85    aww->update_selection_list(id);
86    aww->get_root()->awar(AWAR_REMAP_ALIGNMENT)->write_string("All"); // select "All"
87}
88
89// clear the candidate list
90static void clear_candidates(preserve_para *para) {
91    AW_window         *aww = para->window;
92    AW_selection_list *id  = para->cand_id;
93
94    aww->clear_selection_list(id);
95    aww->insert_default_selection(id, "????", "????");
96    aww->update_selection_list(id);
97
98    aww->get_root()->awar(AWAR_REMAP_CANDIDATE)->write_string(""); // deselect
99}
100
101static long count_bases(const char *data, long len) {
102    long count = 0;
103    for (long i = 0; i<len; ++i) {
104        if (data[i] != '-' && data[i] != '.') {
105            ++count;
106        }
107    }
108    return count;
109}
110
111// count real bases
112// (gb_data should point to ali_xxx/data)
113static long count_bases(GBDATA *gb_data) {
114    long count = 0;
115    switch (GB_read_type(gb_data)) {
116        case GB_STRING:
117            count = count_bases(GB_read_char_pntr(gb_data), GB_read_count(gb_data));
118            break;
119        case GB_BITS:  {
120            char *bitstring = GB_read_as_string(gb_data);
121            long  len       = strlen(bitstring);
122            count           = count_bases(bitstring, len);
123            free(bitstring);
124            break;
125        }
126        default:
127            GB_export_errorf("Data type %s is not supported", GB_get_type_name(gb_data));
128            break;
129    }
130    return count;
131}
132
133// -------------------------
134//      class Candidate
135// -------------------------
136
137class Candidate {
138    string name;                // species/SAI name
139    double score;
140    int    found_alignments;    // counts alignments with data in both databases
141    long   base_count_diff;
142
143public:
144    Candidate(bool is_species, const char *name_, GBDATA *gb_src, GBDATA *gb_dst, const char **ali_names)
145        : name(is_species ? name_ : string("SAI:")+name_)
146    {
147        found_alignments = 0;
148        score            = 0.0;
149        base_count_diff  = 0;
150        bool valid       = true;
151
152        assert(!GB_have_error());
153
154        for (int i = 0; valid && ali_names[i]; ++i) {
155            if (GBDATA *gb_src_data = GBT_read_sequence(gb_src, ali_names[i])) {
156                if (GBDATA *gb_dst_data = GBT_read_sequence(gb_dst, ali_names[i])) {
157                    ++found_alignments;
158
159                    long src_bases  = count_bases(gb_src_data);
160                    long dst_bases  = count_bases(gb_dst_data);
161                    base_count_diff = labs(src_bases-dst_bases);
162
163                    if (GB_have_error()) valid = false;
164
165                    double factor;
166                    if (base_count_diff>5)  factor = 0.2;
167                    else                    factor = (6-base_count_diff)*(1.0/6);
168
169                    long min_bases  = src_bases<dst_bases ? src_bases : dst_bases;
170                    score          += min_bases*factor;
171                }
172            }
173        }
174
175        if (!valid) found_alignments = 0;
176    }
177    ~Candidate() {}
178
179    int has_alignments() const { return found_alignments; }
180    double get_score() const { return score; }
181
182    const char *get_name() const { return name.c_str(); }
183    const char *get_entry() const {
184        bool isSAI = memcmp(get_name(), "SAI:", 4) == 0;
185        return GBS_global_string(isSAI ? "%-24s %i %li %f" : "%-8s %i %li %f",
186                                 get_name(), found_alignments, base_count_diff, score);
187    }
188
189    bool operator < (const Candidate& other) const { // sort highest score first
190        int ali_diff = found_alignments-other.found_alignments;
191
192        if (ali_diff)  {
193            return ali_diff>0;
194        }
195
196        return score > other.score;
197    }
198};
199
200// use SmartPtr to memory-manage Candidate's
201static bool operator < (const SmartPtr<Candidate>& c1, const SmartPtr<Candidate>& c2) {
202    return c1->operator<(*c2);
203}
204typedef set< SmartPtr<Candidate> > Candidates;
205
206// add all candidate species to 'candidates'
207static void find_species_candidates(Candidates& candidates, const char **ali_names) {
208    aw_status("Examining species (kill to stop)");
209    aw_status(0.0);
210
211    // collect names of all species in source database
212    GB_HASH *src_species = GBT_create_species_hash(GLOBAL_gb_merge/*, 1*/); // Note: changed to ignore case (ralf 2007-07-06)
213    long     src_count   = GBS_hash_count_elems(src_species);
214    long     found       = 0;
215    bool     aborted     = false;
216
217    // find existing species in destination database
218    for (GBDATA *gb_dst_species = GBT_first_species(GLOBAL_gb_dest);
219         gb_dst_species && !aborted;
220         gb_dst_species = GBT_next_species(gb_dst_species))
221    {
222        const char *dst_name = GBT_read_name(gb_dst_species);
223
224        if (GBDATA *gb_src_species = (GBDATA*)GBS_read_hash(src_species, dst_name)) {
225            Candidate *cand = new Candidate(true, dst_name, gb_src_species, gb_dst_species, ali_names);
226
227            if (cand->has_alignments() && cand->get_score()>0.0) {
228                candidates.insert(cand);
229            }
230            else {
231                if (GB_have_error()) {
232                    aw_message(GBS_global_string("Invalid adaption candidate '%s' (%s)", dst_name, GB_await_error()));
233                }
234                delete cand;
235            }
236
237            ++found;
238            aw_status(double(found)/src_count);
239            aborted = aw_status() != 0; // test user abort
240        }
241    }
242
243    GBS_free_hash(src_species);
244}
245
246// add all candidate SAIs to 'candidates'
247static void find_SAI_candidates(Candidates& candidates, const char **ali_names) {
248    aw_status("Examining SAIs");
249    aw_status(0.0);
250
251    // collect names of all SAIs in source database
252    GB_HASH *src_SAIs  = GBT_create_SAI_hash(GLOBAL_gb_merge);
253    long     src_count = GBS_hash_count_elems(src_SAIs);
254    long     found       = 0;
255
256    // find existing SAIs in destination database
257    for (GBDATA *gb_dst_SAI = GBT_first_SAI(GLOBAL_gb_dest);
258         gb_dst_SAI;
259         gb_dst_SAI = GBT_next_SAI(gb_dst_SAI))
260    {
261        const char *dst_name = GBT_read_name(gb_dst_SAI);
262
263        if (GBDATA *gb_src_SAI = (GBDATA*)GBS_read_hash(src_SAIs, dst_name)) {
264            Candidate *cand = new Candidate(false, dst_name, gb_src_SAI, gb_dst_SAI, ali_names);
265
266            if (cand->has_alignments() && cand->get_score()>0.0) {
267                candidates.insert(cand);
268            }
269            else {
270                if (GB_have_error()) {
271                    aw_message(GBS_global_string("Invalid adaption candidate 'SAI:%s' (%s)", dst_name, GB_await_error()));
272                }
273                delete cand;
274            }
275
276            ++found;
277            aw_status(double(found)/src_count);
278        }
279    }
280
281    GBS_free_hash(src_SAIs);
282}
283
284// FIND button
285// (rebuild candidates list)
286static void calculate_preserves_cb(AW_window *, AW_CL cl_para) {
287    GB_transaction ta1(GLOBAL_gb_merge);
288    GB_transaction ta2(GLOBAL_gb_dest);
289
290    preserve_para *para = (preserve_para*)cl_para;
291    clear_candidates(para);
292
293    AW_window  *aww     = para->window;
294    AW_root    *aw_root = aww->get_root();
295    char       *ali     = aw_root->awar(AWAR_REMAP_ALIGNMENT)->read_string();
296    Candidates  candidates;
297
298    aw_openstatus("Searching candidates");
299
300    // add candidates
301    if (0 == strcmp(ali, "All")) {
302        char **ali_names = get_global_alignments();
303
304        find_SAI_candidates(candidates, const_cast<const char**>(ali_names));
305        find_species_candidates(candidates, const_cast<const char**>(ali_names));
306
307        GBT_free_names(ali_names);
308    }
309    else {
310        char *ali_names[2] = { ali, 0 };
311        find_SAI_candidates(candidates, const_cast<const char**>(ali_names));
312        find_species_candidates(candidates, const_cast<const char**>(ali_names));
313    }
314
315    int                   count = 0;
316    Candidates::iterator  e     = candidates.end();
317    AW_selection_list    *id    = para->cand_id;
318
319    for (Candidates::iterator i = candidates.begin();
320         i != e && count<5000;
321         ++i, ++count)
322    {
323        string name  = (*i)->get_name();
324        string shown = (*i)->get_entry();
325
326        aww->insert_selection(id, shown.c_str(), name.c_str());
327    }
328    free(ali);
329
330    aw_closestatus();
331
332    aww->update_selection_list(id);
333}
334
335// ADD button
336// (add current selected candidate to references)
337static void add_selected_cb(AW_window *, AW_CL cl_para) {
338    preserve_para *para = (preserve_para*)cl_para;
339    AW_window     *aww  = para->window;
340    AW_root       *awr  = aww->get_root();
341
342    char *current    = awr->awar(AWAR_REMAP_CANDIDATE)->read_string();
343    char *references = awr->awar(AWAR_REMAP_SPECIES_LIST)->read_string();
344    if (references && references[0]) {
345        string ref = string(references);
346        size_t pos = ref.find(current);
347        int    len = strlen(current);
348
349        for (;
350             pos != string::npos;
351             pos = ref.find(current, pos+1))
352        {
353            if (pos == 0 || ref[pos-1] == '\n') {
354                if ((pos+len) == ref.length()) break; // at eos -> skip
355                char behind = ref[pos+len];
356                if (behind == '\n') break; // already there -> skip
357            }
358        }
359
360        if (pos == string::npos) {
361            string appended = ref+'\n'+current;
362            awr->awar(AWAR_REMAP_SPECIES_LIST)->write_string(appended.c_str());
363        }
364    }
365    else {
366        awr->awar(AWAR_REMAP_SPECIES_LIST)->write_string(current);
367    }
368
369    free(references);
370    free(current);
371
372    awr->awar(AWAR_REMAP_ENABLE)->write_int(1);
373}
374
375// CLEAR button
376// (clear references)
377static void clear_references_cb(AW_window *aww) {
378    AW_root *awr = aww->get_root();
379    awr->awar(AWAR_REMAP_SPECIES_LIST)->write_string("");
380    awr->awar(AWAR_REMAP_ENABLE)->write_int(0);
381}
382
383// SELECT PRESERVES window
384AW_window *MG_select_preserves_cb(AW_root *aw_root) {
385    aw_root->awar_string(AWAR_REMAP_ALIGNMENT, "", GLOBAL_gb_dest);
386    aw_root->awar_string(AWAR_REMAP_CANDIDATE, "", GLOBAL_gb_dest);
387
388    AW_window_simple *aws = new AW_window_simple;
389
390    aws->init(aw_root, "SELECT_PRESERVES", "Select adaption candidates");
391    aws->load_xfig("merge/preserves.fig");
392
393    aws->at("close");aws->callback((AW_CB0)AW_POPDOWN);
394    aws->create_button("CLOSE","CLOSE","C");
395
396    aws->at("help");
397    aws->callback(AW_POPUP_HELP,(AW_CL)"mg_preserve.hlp");
398    aws->create_button("HELP","HELP","H");
399
400    aws->at("adapt");
401    aws->label("Adapt alignments");
402    aws->create_toggle(AWAR_REMAP_ENABLE);
403
404    aws->at("reference");
405    aws->create_text_field(AWAR_REMAP_SPECIES_LIST);
406
407    preserve_para *para = new preserve_para; // do not free (is passed to callback)
408    para->window        = aws;
409
410    aws->at("candidate");
411    para->cand_id = aws->create_selection_list(AWAR_REMAP_CANDIDATE, 0, "", 10, 30);
412
413    aws->at("ali");
414    para->ali_id = aws->create_selection_list(AWAR_REMAP_ALIGNMENT, 0, "", 10, 30);
415
416    aws->at("find");
417    aws->callback(calculate_preserves_cb, (AW_CL)para);
418    aws->create_autosize_button("FIND", "Find candidates", "F", 1);
419
420    {
421        GB_transaction ta1(GLOBAL_gb_merge);
422        GB_transaction ta2(GLOBAL_gb_dest);
423
424        init_alignments(para);
425        clear_candidates(para);
426    }
427
428    aws->button_length(8);
429
430    aws->at("add");
431    aws->callback(add_selected_cb, (AW_CL)para);
432    aws->create_button("ADD", "Add", "A");
433
434    aws->at("clear");
435    aws->callback(clear_references_cb);
436    aws->create_button("CLEAR", "Clear", "C");
437
438    return aws;
439}
440
441
442
443
Note: See TracBrowser for help on using the repository browser.