source: tags/svn.1.5.4/NTREE/ad_spec.cxx

Last change on this file was 7801, checked in by westram, 14 years ago

merge from dev [7710]

  • resolve some nesting in library dependencies
    • allows unit tests in GENOM and GENOM_IMPORT
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ad_spec.cxx                                       //
4//   Purpose   : Create and modify species and SAI.                //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "map_viewer.hxx"
12#include "nt_internal.h"
13#include "ntree.hxx"
14
15#include <dbui.h>
16
17#include <awt_www.hxx>
18#include <awt_canvas.hxx>
19
20#include <aw_awars.hxx>
21#include <aw_msg.hxx>
22#include <aw_root.hxx>
23
24#include <arb_progress.h>
25#include <arb_defs.h>
26
27#include <cctype>
28
29
30#define nt_assert(bed) arb_assert(bed)
31
32extern GBDATA *GLOBAL_gb_main;
33
34static const char * const SAI_COUNTED_CHARS = "COUNTED_CHARS";
35
36void NT_count_different_chars(AW_window *, AW_CL cl_gb_main, AW_CL) {
37    // @@@ extract algorithm and call extracted from testcode
38    ARB_ERROR  error;
39    GBDATA    *gb_main = (GBDATA*)cl_gb_main;
40
41    error = GB_begin_transaction(gb_main);                      // open transaction
42
43    char *alignment_name = GBT_get_default_alignment(gb_main);  // info about sequences
44    int   alignment_len  = GBT_get_alignment_len(gb_main, alignment_name);
45    int   is_amino       = GBT_is_alignment_protein(gb_main, alignment_name);
46
47    if (!error) {
48        const int MAXLETTER   = 256;
49        const int FIRSTLETTER = 0;
50
51        typedef bool letterOccurs[MAXLETTER];
52
53        letterOccurs *occurs = (letterOccurs*)malloc(sizeof(*occurs)*alignment_len);
54        for (int i = 0; i<MAXLETTER; ++i) {
55            for (int p = 0; p<alignment_len; ++p) {
56                occurs[p][i] = false;
57            }
58        }
59
60        // loop over all marked species
61        {
62            int          all_marked = GBT_count_marked_species(gb_main);
63            arb_progress progress("Counting different characters", all_marked);
64
65            for (GBDATA *gb_species = GBT_first_marked_species(gb_main);
66                 gb_species && !error;
67                 gb_species = GBT_next_marked_species(gb_species))
68            {
69                GBDATA *gb_ali = GB_entry(gb_species, alignment_name); // search the sequence database entry ( ali_xxx/data )
70                if (gb_ali) {
71                    GBDATA *gb_data = GB_entry(gb_ali, "data");
72                    if (gb_data) {
73                        const char * const seq = GB_read_char_pntr(gb_data);
74                        if (seq) {
75                            for (int i=0; i< alignment_len; ++i) {
76                                unsigned char c = seq[i];
77                                if (!c) break;
78
79                                occurs[i][c-FIRSTLETTER] = true;
80                            }
81                        }
82                    }
83                }
84                progress.inc_and_check_user_abort(error);
85            }
86        }
87
88        if (!error) {
89
90            char filter[256];
91            if (is_amino) for (int c = 0; c<256; ++c) filter[c] = isupper(c) && (strchr("BJOUZ", c) == 0);
92            else          for (int c = 0; c<256; ++c) filter[c] = (strchr("ACGTU", c) != 0);
93
94            char result[alignment_len+1];
95            for (int i=0; i<alignment_len; i++) {
96                int sum = 0;
97                for (int c = 'A'; c < 'Z'; ++c) {
98                    if (filter[c]) {
99                        sum += (occurs[i][c] || occurs[i][tolower(c)]);
100                    }
101                }
102                result[i] = sum<10 ? '0'+sum : 'A'-10+sum;
103            }
104            result[alignment_len] = 0;
105
106            {
107                GBDATA *gb_sai     = GBT_find_or_create_SAI(gb_main, SAI_COUNTED_CHARS);
108                if (!gb_sai) error = GB_await_error();
109                else {
110                    GBDATA *gb_data     = GBT_add_data(gb_sai, alignment_name, "data", GB_STRING);
111                    if (!gb_data) error = GB_await_error();
112                    else    error       = GB_write_string(gb_data, result);
113                }
114            }
115        }
116
117        free(occurs);
118    }
119
120    free(alignment_name);
121
122    GB_end_transaction_show_error(gb_main, error, aw_message);
123}
124
125void NT_create_sai_from_pfold(AW_window *aww, AW_CL ntw, AW_CL) {
126    /*! \brief Creates an SAI from protein secondary structure of a selected species.
127     *
128     *  \param[in] aww AW_window
129     *  \param[in] ntw AWT_canvas
130     *
131     *  The function takes the currently selected species and searches for the field
132     *  "sec_struct". A new SAI is created using the data in this field. A simple input
133     *  window allows the user to change the default name ([species name]_pfold) for
134     *  the new SAI.
135     *
136     *  \note The import filter "dssp_all.ift" allows for importing the amino acid sequence
137     *        as well as the protein secondary structure from a dssp file and the structure
138     *        is stored in the field "sec_struct". That way, secondary structure can be
139     *        aligned along with the sequence manually and can later be extracted to create
140     *        an SAI.
141     *
142     *  \attention The import filter "dssp_2nd_struct.ift" extracts only the protein
143     *             secondary structure which is stored as alignment data. SAIs can simply
144     *             be created from these species via move_species_to_extended().
145     */
146
147    GB_ERROR  error      = 0;
148    GB_begin_transaction(GLOBAL_gb_main);
149    char     *sai_name   = 0;
150    char     *sec_struct = 0;
151    bool      canceled   = false;
152
153    // get the selected species
154    char *species_name = aww->get_root()->awar(AWAR_SPECIES_NAME)->read_string();
155    GBDATA *gb_species = 0;
156    if (!strcmp(species_name, "") || !(gb_species = GBT_find_species(GLOBAL_gb_main, species_name))) {
157        error = "Please select a species first.";
158    }
159    else {
160        // search for the field "sec_struct"
161        GBDATA *gb_species_sec_struct = GB_entry(gb_species, "sec_struct");
162        if (!gb_species_sec_struct) {
163            error = "Field \"sec_struct\" not found or empty. Please select another species.";
164        }
165        else if (!(sec_struct = GB_read_string(gb_species_sec_struct))) {
166            error = "Couldn't read field \"sec_struct\". Is it empty?";
167        }
168        else {
169            // generate default name and name input field for the new SAI
170            {
171                char *sai_default_name = GBS_global_string_copy("%s%s", species_name, strstr(species_name, "_pfold") ? "" : "_pfold");
172                sai_name         = aw_input("Name of SAI to create:", sai_default_name);
173                free(sai_default_name);
174            }
175
176            if (!sai_name) {
177                canceled = true;
178            }
179            else if (strspn(sai_name, " ") == strlen(sai_name)) {
180                error = "Name of SAI is empty. Please enter a valid name.";
181            }
182            else {
183                GBDATA *gb_sai_data = GBT_get_SAI_data(GLOBAL_gb_main);
184                GBDATA *gb_sai      = GBT_find_SAI_rel_SAI_data(gb_sai_data, sai_name);
185                char   *ali_name    = GBT_get_default_alignment(GLOBAL_gb_main);
186
187                if (gb_sai) {
188                    error = "SAI with the same name already exists. Please enter another name.";
189                }
190                else {
191                    // create SAI container and copy fields from the species to the SAI
192                    gb_sai                   = GB_create_container(gb_sai_data, "extended");
193                    GBDATA *gb_species_field = GB_child(gb_species);
194
195                    while (gb_species_field && !error) {
196                        char   *key          = GB_read_key(gb_species_field);
197                        GBDATA *gb_sai_field = GB_search(gb_sai, GB_read_key(gb_species_field), GB_read_type(gb_species_field));
198
199                        if (strcmp(key, "name") == 0) { // write the new name
200                            error = GB_write_string(gb_sai_field, sai_name);
201                        }
202                        else if (strcmp(key, "sec_struct") == 0) { // write contents from the field "sec_struct" to the alignment data
203                            GBDATA *gb_sai_ali     = GB_search(gb_sai, ali_name, GB_CREATE_CONTAINER);
204                            if (!gb_sai_ali) error = GB_await_error();
205                            else    error          = GBT_write_string(gb_sai_ali, "data", sec_struct);
206                        }
207                        else if (strcmp(key, "acc") != 0 && strcmp(key, ali_name) != 0) { // don't copy "acc" and the old alignment data
208                            error = GB_copy(gb_sai_field, gb_species_field);
209                        }
210                        gb_species_field = GB_nextChild(gb_species_field);
211                        free(key);
212                    }
213
214                    // generate accession number and delete field "sec_struct" from the SAI
215                    if (!error) {
216                        // TODO: is it necessary that a new acc is generated here?
217                        GBDATA *gb_sai_acc = GB_search(gb_sai, "acc", GB_FIND);
218                        if (gb_sai_acc) {
219                            GB_delete(gb_sai_acc);
220                            GBT_gen_accession_number(gb_sai, ali_name);
221                        }
222                        GBDATA *gb_sai_sec_struct = GB_search(gb_sai, "sec_struct", GB_FIND);
223                        if (gb_sai_sec_struct) GB_delete(gb_sai_sec_struct);
224                        aww->get_root()->awar(AWAR_SAI_NAME)->write_string(sai_name);
225                    }
226                }
227            }
228        }
229    }
230
231    if (canceled) error = "Aborted by user";
232
233    GB_end_transaction_show_error(GLOBAL_gb_main, error, aw_message);
234
235    if (!error) {
236        AW_window *sai_info = NT_create_extendeds_window(aww->get_root());
237        // TODO: why doesn't info box show anything on first startup? proper refresh needed?
238        sai_info->activate();
239        ((AWT_canvas *)ntw)->refresh(); // refresh doesn't work, I guess...
240    }
241
242    free(species_name);
243    free(sai_name);
244    free(sec_struct);
245}
246
247void launch_MapViewer_cb(GBDATA *gbd, AD_MAP_VIEWER_TYPE type) {
248    GB_ERROR error = GB_push_transaction(GLOBAL_gb_main);
249
250    if (!error) {
251        const char *species_name    = "";
252        GBDATA     *gb_species_data = GB_search(GLOBAL_gb_main, "species_data", GB_CREATE_CONTAINER);
253
254        if (gbd && GB_get_father(gbd) == gb_species_data) {
255            species_name = GBT_read_name(gbd);
256        }
257
258        AW_root::SINGLETON->awar(AWAR_SPECIES_NAME)->write_string(species_name);
259    }
260
261    if (!error && gbd && type == ADMVT_WWW) {
262        GBDATA *gb_name       = GB_entry(gbd, "name");
263        if (!gb_name) gb_name = GB_entry(gbd, "group_name"); // bad hack, should work
264
265        const char *name = gb_name ? GB_read_char_pntr(gb_name) : "noname";
266        error = awt_openURL_by_gbd(GLOBAL_NT.awr, GLOBAL_gb_main, gbd, name);
267    }
268
269    error = GB_end_transaction(GLOBAL_gb_main, error);
270    if (error) aw_message(error);
271}
272
273
274// --------------------------------------------------------------------------------
275
276#ifdef UNIT_TESTS
277#include <test_unit.h>
278#include <arb_unit_test.h>
279
280static uint32_t counted_chars_checksum(GBDATA *gb_main)  {
281    GB_transaction ta(gb_main);
282
283    GBDATA *gb_sai;
284    GBDATA *gb_ali;
285    GBDATA *gb_counted_chars;
286
287    char *ali_name = GBT_get_default_alignment(gb_main);
288
289    TEST_ASSERT_RESULT__NOERROREXPORTED(gb_sai = GBT_expect_SAI(gb_main, SAI_COUNTED_CHARS));
290    TEST_ASSERT_RESULT__NOERROREXPORTED(gb_ali = GB_entry(gb_sai, ali_name));
291    TEST_ASSERT_RESULT__NOERROREXPORTED(gb_counted_chars = GB_entry(gb_ali, "data"));
292
293    const char *data = GB_read_char_pntr(gb_counted_chars);
294
295    free(ali_name);
296
297    return GBS_checksum(data, 0, NULL);
298}
299
300void TEST_count_chars() {
301    // calculate SAI for test DBs
302
303    arb_suppress_progress silence;
304    GB_shell              shell;
305
306    for (int prot = 0; prot<2; ++prot) {
307        GBDATA *gb_main;
308        TEST_ASSERT_RESULT__NOERROREXPORTED(gb_main = GB_open(prot ? "TEST_prot.arb" : "TEST_nuc.arb", "rw"));
309
310        GBT_mark_all(gb_main, 1);
311        NT_count_different_chars(NULL, (AW_CL)gb_main, 0);
312
313        uint32_t expected = prot ? 0x4fa63fa0 : 0xefb05e4e;
314        TEST_ASSERT_EQUAL(counted_chars_checksum(gb_main), expected);
315
316        GB_close(gb_main);
317    }
318}
319void TEST_SLOW_count_chars() {
320    // calculate a real big test alignment
321    //
322    // the difference to TEST_count_chars() is just in size of alignment.
323    // NT_count_different_chars() crashes for big alignments when running in gdb
324    arb_suppress_progress silence;
325    GB_shell              shell;
326    {
327        arb_unit_test::test_alignment_data data_source[] = {
328            { 1, "s1", "ACGT" },
329            { 1, "s2", "ACGTN" },
330            { 1, "s3", "NANNAN" },
331            { 1, "s4", "GATTACA" },
332        };
333
334        const int alilen = 50000;
335        const int count  = ARRAY_ELEMS(data_source);
336
337        char *longSeq[count];
338        for (int c = 0; c<count; ++c) {
339            char *dest = longSeq[c] = (char*)malloc(alilen+1);
340
341            const char *source = data_source[c].data;
342            int         len    = strlen(source);
343
344            for (int p = 0; p<alilen; ++p) {
345                dest[p] = source[p%len];
346            }
347            dest[alilen] = 0;
348           
349            data_source[c].data = dest;
350        }
351
352        ARB_ERROR  error;
353        GBDATA    *gb_main = TEST_CREATE_DB(error, "ali_test", data_source, false);
354
355        TEST_ASSERT_NO_ERROR(error.deliver());
356
357        NT_count_different_chars(NULL, (AW_CL)gb_main, 0);
358
359        // TEST_ASSERT_EQUAL(counted_chars_checksum(gb_main), 0x1d34a14f);
360        // TEST_ASSERT_EQUAL(counted_chars_checksum(gb_main), 0x609d788b);
361        TEST_ASSERT_EQUAL(counted_chars_checksum(gb_main), 0xccdfa527);
362
363        for (int c = 0; c<count; ++c) {
364            free(longSeq[c]);
365        }
366
367        GB_close(gb_main);
368    }
369}
370
371#endif // UNIT_TESTS
372
Note: See TracBrowser for help on using the repository browser.