source: tags/svn.1.5.4/MERGE/MG_preserves.cxx

Last change on this file was 7916, checked in by westram, 13 years ago
  • removed AWAR_DTREE_REFRESH (→ AWAR_TREE_REFRESH)
  • DRYed AWAR_TREE_REFRESH
  • loosened coupling between aw_awar.hxx and aw_awar_defs.hxx (former aw_awars.hxx)
    • aw_awars.hxx now includes both
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 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 "merge.hxx"
16#include "MG_adapt_ali.hxx"
17
18#include <aw_awar.hxx>
19#include <aw_root.hxx>
20#include <aw_msg.hxx>
21#include <arb_progress.h>
22#include <arbdbt.h>
23
24#include <set>
25#include <string>
26
27using namespace std;
28
29// find species/SAIs to preserve alignment
30
31#define AWAR_REMAP_CANDIDATE     "tmp/merge/remap_candidates"
32#define AWAR_REMAP_ALIGNMENT     "tmp/merge/remap_alignment"
33#define AWAR_REMAP_SEL_REFERENCE "tmp/merge/remap_reference"
34
35struct preserve_para {
36    AW_window         *window;
37    AW_selection_list *ali_id;                      // alignments
38    AW_selection_list *cand_id;                     // reference candidates
39    AW_selection_list *ref_id;                      // used references
40};
41
42static void get_global_alignments(ConstStrArray& ali_names) {
43    // get all alignment names available in both databases
44    GBT_get_alignment_names(ali_names, GLOBAL_gb_merge);
45    GBDATA *gb_presets = GB_search(GLOBAL_gb_dest, "presets", GB_CREATE_CONTAINER);
46
47    int i;
48    for (i = 0; ali_names[i]; ++i) {
49        GBDATA *gb_ali_name = GB_find_string(gb_presets, "alignment_name", ali_names[i], GB_IGNORE_CASE, SEARCH_GRANDCHILD);
50        if (!gb_ali_name) ali_names.remove(i--);
51    }
52}
53
54static void init_alignments(preserve_para *para) {
55    // initialize the alignment selection list
56    ConstStrArray ali_names;
57    get_global_alignments(ali_names);
58    para->window->init_selection_list_from_array(para->ali_id, ali_names, "All");
59}
60
61static void clear_candidates(preserve_para *para) {
62    // clear the candidate list
63    AW_window         *aww = para->window;
64    AW_selection_list *id  = para->cand_id;
65
66    aww->clear_selection_list(id);
67    aww->insert_default_selection(id, "????", "????");
68    aww->update_selection_list(id);
69}
70
71static long count_bases(const char *data, long len) {
72    long count = 0;
73    for (long i = 0; i<len; ++i) {
74        if (data[i] != '-' && data[i] != '.') {
75            ++count;
76        }
77    }
78    return count;
79}
80
81// count real bases
82// (gb_data should point to ali_xxx/data)
83static long count_bases(GBDATA *gb_data) {
84    long count = 0;
85    switch (GB_read_type(gb_data)) {
86        case GB_STRING:
87            count = count_bases(GB_read_char_pntr(gb_data), GB_read_count(gb_data));
88            break;
89        case GB_BITS: {
90            char *bitstring = GB_read_as_string(gb_data);
91            long  len       = strlen(bitstring);
92            count           = count_bases(bitstring, len);
93            free(bitstring);
94            break;
95        }
96        default:
97            GB_export_errorf("Data type %s is not supported", GB_get_type_name(gb_data));
98            break;
99    }
100    return count;
101}
102
103// -------------------------
104//      class Candidate
105// -------------------------
106
107class Candidate {
108    string name;                // species/SAI name
109    double score;
110    int    found_alignments;    // counts alignments with data in both databases
111    long   base_count_diff;
112
113public:
114    Candidate(bool is_species, const char *name_, GBDATA *gb_src, GBDATA *gb_dst, const CharPtrArray& ali_names)
115        : name(is_species ? name_ : string("SAI:")+name_)
116    {
117        found_alignments = 0;
118        score            = 0.0;
119        base_count_diff  = 0;
120        bool valid       = true;
121
122        mg_assert(!GB_have_error());
123
124        for (int i = 0; valid && ali_names[i]; ++i) {
125            if (GBDATA *gb_src_data = GBT_read_sequence(gb_src, ali_names[i])) {
126                if (GBDATA *gb_dst_data = GBT_read_sequence(gb_dst, ali_names[i])) {
127                    ++found_alignments;
128
129                    long src_bases  = count_bases(gb_src_data);
130                    long dst_bases  = count_bases(gb_dst_data);
131                    base_count_diff = labs(src_bases-dst_bases);
132
133                    if (GB_have_error()) valid = false;
134
135                    double factor;
136                    if (base_count_diff>5)  factor = 0.2;
137                    else                    factor = (6-base_count_diff)*(1.0/6);
138
139                    long min_bases  = src_bases<dst_bases ? src_bases : dst_bases;
140                    score          += min_bases*factor;
141                }
142            }
143        }
144
145        if (!valid) found_alignments = 0;
146    }
147    ~Candidate() {}
148
149    int has_alignments() const { return found_alignments; }
150    double get_score() const { return score; }
151
152    const char *get_name() const { return name.c_str(); }
153    const char *get_entry() const {
154        return GBS_global_string("%24s  %i %li %f", get_name(), found_alignments, base_count_diff, score);
155    }
156
157    bool operator < (const Candidate& other) const { // sort highest score first
158        int ali_diff = found_alignments-other.found_alignments;
159        if (ali_diff) return ali_diff>0;
160        return score > other.score;
161    }
162};
163
164// use SmartPtr to memory-manage Candidate's
165static bool operator < (const SmartPtr<Candidate>& c1, const SmartPtr<Candidate>& c2) {
166    return c1->operator<(*c2);
167}
168typedef set< SmartPtr<Candidate> > Candidates;
169
170static void find_species_candidates(Candidates& candidates, const CharPtrArray& ali_names) {
171    // collect names of all species in source database
172    GB_HASH      *src_species = GBT_create_species_hash(GLOBAL_gb_merge);
173    long          src_count   = GBS_hash_count_elems(src_species);
174    arb_progress  progress("Examining species", src_count);
175    bool          aborted     = false;
176
177    // find existing species in destination database
178    for (GBDATA *gb_dst_species = GBT_first_species(GLOBAL_gb_dest);
179         gb_dst_species && !aborted;
180         gb_dst_species = GBT_next_species(gb_dst_species))
181    {
182        const char *dst_name = GBT_read_name(gb_dst_species);
183
184        if (GBDATA *gb_src_species = (GBDATA*)GBS_read_hash(src_species, dst_name)) {
185            Candidate *cand = new Candidate(true, dst_name, gb_src_species, gb_dst_species, ali_names);
186
187            if (cand->has_alignments() && cand->get_score()>0.0) {
188                candidates.insert(cand);
189            }
190            else {
191                if (GB_have_error()) {
192                    aw_message(GBS_global_string("Invalid adaption candidate '%s' (%s)", dst_name, GB_await_error()));
193                }
194                delete cand;
195            }
196
197            progress.inc();
198            aborted = progress.aborted();
199        }
200    }
201
202    GBS_free_hash(src_species);
203}
204
205static void find_SAI_candidates(Candidates& candidates, const CharPtrArray& ali_names) {
206    // add all candidate SAIs to 'candidates'
207    GB_HASH      *src_SAIs  = GBT_create_SAI_hash(GLOBAL_gb_merge);
208    long          src_count = GBS_hash_count_elems(src_SAIs);
209    arb_progress  progress("Examining SAIs", src_count);
210
211    // find existing SAIs in destination database
212    for (GBDATA *gb_dst_SAI = GBT_first_SAI(GLOBAL_gb_dest);
213         gb_dst_SAI;
214         gb_dst_SAI = GBT_next_SAI(gb_dst_SAI))
215    {
216        const char *dst_name = GBT_read_name(gb_dst_SAI);
217
218        if (GBDATA *gb_src_SAI = (GBDATA*)GBS_read_hash(src_SAIs, dst_name)) {
219            Candidate *cand = new Candidate(false, dst_name, gb_src_SAI, gb_dst_SAI, ali_names);
220
221            if (cand->has_alignments() && cand->get_score()>0.0) {
222                candidates.insert(cand);
223            }
224            else {
225                if (GB_have_error()) {
226                    aw_message(GBS_global_string("Invalid adaption candidate 'SAI:%s' (%s)", dst_name, GB_await_error()));
227                }
228                delete cand;
229            }
230
231            progress.inc();
232        }
233    }
234
235    GBS_free_hash(src_SAIs);
236}
237
238static void calculate_preserves_cb(AW_window *, AW_CL cl_para) {
239    // FIND button (rebuild candidates list)
240
241    GB_transaction ta1(GLOBAL_gb_merge);
242    GB_transaction ta2(GLOBAL_gb_dest);
243
244    preserve_para *para = (preserve_para*)cl_para;
245    clear_candidates(para);
246
247    AW_window  *aww     = para->window;
248    AW_root    *aw_root = aww->get_root();
249    const char *ali     = aw_root->awar(AWAR_REMAP_ALIGNMENT)->read_char_pntr();
250    Candidates  candidates;
251
252    arb_progress("Searching candidates");
253
254    // add candidates
255    {
256        ConstStrArray ali_names;
257        if (0 == strcmp(ali, "All")) {
258            get_global_alignments(ali_names);
259        }
260        else {
261            ali_names.put(ali);
262        }
263        find_SAI_candidates(candidates, ali_names);
264        find_species_candidates(candidates, ali_names);
265    }
266
267    int                   count = 0;
268    Candidates::iterator  e     = candidates.end();
269    AW_selection_list    *id    = para->cand_id;
270
271    for (Candidates::iterator i = candidates.begin();
272         i != e && count<5000;
273         ++i, ++count)
274    {
275        string name  = (*i)->get_name();
276        string shown = (*i)->get_entry();
277
278        aww->insert_selection(id, shown.c_str(), name.c_str());
279    }
280
281    aww->update_selection_list(id);
282}
283
284
285
286static void read_references(ConstStrArray& refs, AW_root *aw_root)  {
287    char *ref_string = aw_root->awar(AWAR_REMAP_SPECIES_LIST)->read_string();
288    GBT_splitNdestroy_string(refs, ref_string, " \n,;", true);
289}
290static void write_references(AW_root *aw_root, const CharPtrArray& ref_array) {
291    char *ref_string = GBT_join_names(ref_array, '\n');
292    aw_root->awar(AWAR_REMAP_SPECIES_LIST)->write_string(ref_string);
293    aw_root->awar(AWAR_REMAP_ENABLE)->write_int(ref_string[0] != 0);
294    free(ref_string);
295}
296static void select_reference(AW_root *aw_root, const char *ref_to_select) {
297    aw_root->awar(AWAR_REMAP_SEL_REFERENCE)->write_string(ref_to_select);
298}
299static char *get_selected_reference(AW_root *aw_root) {
300    return aw_root->awar(AWAR_REMAP_SEL_REFERENCE)->read_string();
301}
302
303static void refresh_reference_list_cb(AW_root *aw_root, AW_CL cl_para) {
304    preserve_para *para = (preserve_para*)cl_para;
305    ConstStrArray  refs;
306    read_references(refs, aw_root);
307    para->window->init_selection_list_from_array(para->ref_id, refs, "");
308}
309
310static void add_selected_cb(AW_window *, AW_CL cl_para) {
311    // ADD button (add currently selected candidate to references)
312
313    preserve_para *para    = (preserve_para*)cl_para;
314    AW_root       *aw_root = para->window->get_root();
315    ConstStrArray  refs;
316    read_references(refs, aw_root);
317
318    char *candidate  = aw_root->awar(AWAR_REMAP_CANDIDATE)->read_string();
319    char *selected   = get_selected_reference(aw_root);
320    int   cand_index = GBT_names_index_of(refs, candidate);
321    int   sel_index  = GBT_names_index_of(refs, selected);
322
323    if (cand_index == -1) GBT_names_add(refs, sel_index+1, candidate);
324    else                  GBT_names_move(refs, cand_index, sel_index);
325
326    write_references(aw_root, refs);
327    select_reference(aw_root, candidate);
328
329    free(selected);
330    free(candidate);
331
332    para->window->move_selection(para->cand_id, 1); 
333}
334
335static void clear_references_cb(AW_window *aww) {
336    // CLEAR button (clear references)
337    aww->get_root()->awar(AWAR_REMAP_SPECIES_LIST)->write_string("");
338}
339
340static void del_reference_cb(AW_window *aww) {
341    AW_root       *aw_root = aww->get_root();
342    ConstStrArray  refs;
343    read_references(refs, aw_root);
344
345    char *selected  = get_selected_reference(aw_root);
346    int   sel_index = GBT_names_index_of(refs, selected);
347
348    if (sel_index >= 0) {
349        select_reference(aw_root, refs[sel_index+1]);
350        GBT_names_erase(refs, sel_index);
351        write_references(aw_root, refs);
352    }
353
354    free(selected);
355}
356
357static void lower_reference_cb(AW_window *aww) {
358    AW_root       *aw_root = aww->get_root();
359    ConstStrArray  refs;
360    read_references(refs, aw_root);
361
362    char *selected  = get_selected_reference(aw_root);
363    int   sel_index = GBT_names_index_of(refs, selected);
364
365    if (sel_index >= 0) {
366        GBT_names_move(refs, sel_index, sel_index+1);
367        write_references(aw_root, refs);
368    }
369
370    free(selected);
371}
372static void raise_reference_cb(AW_window *aww) {
373    AW_root       *aw_root = aww->get_root();
374    ConstStrArray  refs;
375    read_references(refs, aw_root);
376
377    char *selected  = get_selected_reference(aw_root);
378    int   sel_index = GBT_names_index_of(refs, selected);
379
380    if (sel_index > 0) {
381        GBT_names_move(refs, sel_index, sel_index-1);
382        write_references(aw_root, refs);
383    }
384
385    free(selected);
386}
387
388static void test_references_cb(AW_window *aww) {
389    char           *reference_species_names = aww->get_root()->awar(AWAR_REMAP_SPECIES_LIST)->read_string();
390    GB_transaction  tm(GLOBAL_gb_merge);
391    GB_transaction  td(GLOBAL_gb_dest);
392   
393    MG_remaps test_mapping(GLOBAL_gb_merge, GLOBAL_gb_dest, true, reference_species_names); // will raise aw_message's in case of problems
394
395    free(reference_species_names);
396}
397
398static void init_preserve_awars(AW_root *aw_root) {
399    aw_root->awar_string(AWAR_REMAP_ALIGNMENT,     "", GLOBAL_gb_dest);
400    aw_root->awar_string(AWAR_REMAP_CANDIDATE,     "", GLOBAL_gb_dest);
401    aw_root->awar_string(AWAR_REMAP_SEL_REFERENCE, "", GLOBAL_gb_dest);
402}
403
404AW_window *MG_select_preserves_cb(AW_root *aw_root) {
405    // SELECT PRESERVES window
406    init_preserve_awars(aw_root);
407
408    AW_window_simple *aws = new AW_window_simple;
409
410    aws->init(aw_root, "SELECT_PRESERVES", "Select adaption candidates");
411    aws->load_xfig("merge/preserves.fig");
412
413    aws->at("close"); aws->callback((AW_CB0)AW_POPDOWN);
414    aws->create_button("CLOSE", "CLOSE", "C");
415
416    aws->at("help");
417    aws->callback(AW_POPUP_HELP, (AW_CL)"mg_preserve.hlp");
418    aws->create_button("HELP", "HELP", "H");
419
420    // ----------
421
422    preserve_para *para = new preserve_para; // do not free (is passed to callback)
423    para->window        = aws;
424   
425    aws->at("ali");
426    para->ali_id = aws->create_selection_list(AWAR_REMAP_ALIGNMENT, 0, "", 10, 30);
427
428    // ----------
429   
430    aws->at("adapt");
431    aws->label("Adapt alignments");
432    aws->create_toggle(AWAR_REMAP_ENABLE);
433
434    aws->at("reference");
435    // aws->create_text_field(AWAR_REMAP_SPECIES_LIST); // @@@ needs to be a selection list!
436    para->ref_id = aws->create_selection_list(AWAR_REMAP_SEL_REFERENCE, 0, "", 10, 30);
437
438    aws->button_length(8);
439
440    aws->at("clear");
441    aws->callback(clear_references_cb);
442    aws->create_button("CLEAR", "Clear", "C");
443
444    aws->at("del");
445    aws->callback(del_reference_cb);
446    aws->create_button("DEL", "Del", "L");
447
448    aws->at("up");
449    aws->callback(raise_reference_cb);
450    aws->create_button("UP", "Up", "U");
451
452    aws->at("down");
453    aws->callback(lower_reference_cb);
454    aws->create_button("DOWN", "Down", "D");
455
456    aws->at("test");
457    aws->callback(test_references_cb);
458    aws->create_button("TEST", "Test", "T");
459   
460    // ----------
461
462    aws->at("find");
463    aws->callback(calculate_preserves_cb, (AW_CL)para);
464    aws->create_autosize_button("FIND", "Find candidates", "F", 1);
465
466    aws->at("add");
467    aws->callback(add_selected_cb, (AW_CL)para);
468    aws->create_button("ADD", "Add", "A");
469
470    aws->at("candidate");
471    para->cand_id = aws->create_selection_list(AWAR_REMAP_CANDIDATE, 0, "", 10, 30);
472
473    {
474        GB_transaction ta1(GLOBAL_gb_merge);
475        GB_transaction ta2(GLOBAL_gb_dest);
476
477        init_alignments(para);
478        clear_candidates(para);
479    }
480
481    {
482        AW_awar *awar_list = aw_root->awar(AWAR_REMAP_SPECIES_LIST);
483        awar_list->add_callback(refresh_reference_list_cb, (AW_CL)para);
484        awar_list->touch(); // trigger callback
485    }
486
487    return aws;
488}
489
490
491
492
Note: See TracBrowser for help on using the repository browser.