source: tags/cvs_2_svn/MERGE/MG_preserves.cxx

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