source: tags/ms_r17q3/NTREE/ad_spec.cxx

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