source: cpp/frams/genetics/geno.cpp @ 521

Last change on this file since 521 was 521, checked in by Maciej Komosinski, 8 years ago

Extended error messages for invalid genotype format declaration

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
2// Copyright (C) 1999-2015  Maciej Komosinski and Szymon Ulatowski.
3// See LICENSE.txt for details.
4
5#include "geno.h"
6#include "genoconv.h"
7#include <common/loggers/loggers.h>
8#include <common/stl-util.h>
9#include <frams/model/model.h>
10
11THREAD_LOCAL_DEF_PTR(Geno::Validators, geno_validators);
12THREAD_LOCAL_DEF_PTR(GenoConvManager, geno_converters);
13
14Geno::Validators* Geno::getValidators() {return tlsGetPtr(geno_validators);}
15GenoConvManager* Geno::getConverters() {return tlsGetPtr(geno_converters);}
16
17Geno::Validators* Geno::useValidators(Validators* val)
18{return tlsSetPtr(geno_validators,val);}
19GenoConvManager* Geno::useConverters(GenoConvManager* gcm)
20{return tlsSetPtr(geno_converters,gcm);}
21
22void Geno::init(const SString& genstring, char genformat, const SString& genname, const SString& comment)
23{
24        refcount = 1;
25        owner = 0;
26        f0gen = 0;
27        mapinshift = 0;
28        mapoutshift = 0;
29        isvalid = -1;
30        SString gencopy(genstring);
31        if (genformat == -1)
32        { // unknown format
33                genformat = '1';
34                if (genstring.charAt(0) == '/')
35                {
36                        int end, error_end=-1;
37                        switch (genstring.charAt(1))
38                        {
39                        case '/':
40                                genformat = genstring.charAt(2);
41                                if ((genformat=='\0')||isspace(genformat))
42                                        genformat=INVALID_FORMAT;
43                                if ((end = genstring.indexOf('\n')) >= 0)
44                                {
45                                        error_end=end;
46                                        if (end!=3) genformat=INVALID_FORMAT;
47                                        gencopy = genstring.substr(end + 1);
48                                        mapinshift = end + 1;
49                                }
50                                else
51                                {
52                                        if (genstring.len()!=3) genformat=INVALID_FORMAT;
53                                        gencopy = 0;
54                                        mapinshift = genstring.len();
55                                }
56                                break;
57                        case '*':
58                                genformat = genstring.charAt(2);
59                                if ((genformat=='\0')||isspace(genformat))
60                                        genformat=INVALID_FORMAT;
61                                if ((end = genstring.indexOf("*/")) >= 0)
62                                {
63                                        error_end=end+2;
64                                        if (end!=3) genformat=INVALID_FORMAT;
65                                        gencopy = genstring.substr(end + 2);
66                                        mapinshift = end + 2;
67                                }
68                                else
69                                {
70                                        if (genstring.len()!=5) genformat=INVALID_FORMAT;
71                                        gencopy = 0;
72                                        mapinshift = genstring.len();
73                                }
74                                break;
75                        }
76                if (genformat==INVALID_FORMAT)
77                        {
78                        SString cut;
79                        if (error_end<0) error_end=genstring.len();
80                        static const int MAX_ERROR=20;
81                        if (error_end>MAX_ERROR)
82                                cut=genstring.substr(0,MAX_ERROR)+"...";
83                        else
84                                cut=genstring.substr(0,error_end);
85                        int lf=cut.indexOf('\n');
86                        if (lf>=0) cut=cut.substr(0,lf);
87                        logPrintf("Geno","init",LOG_ERROR,"Invalid genotype format declaration: '%s'%s",cut.c_str(),genname.len()?SString::sprintf(" in '%s'",genname.c_str()).c_str():"");
88                        }
89
90                }
91        }
92
93        gen = gencopy;
94        format = genformat;
95        name = genname;
96        txt = comment;
97        multiline = (strchr(gen.c_str(), '\n') != 0);
98        // mapoutshift...?
99}
100
101void Geno::freeF0()
102{
103        if (f0gen) { delete f0gen; f0gen = 0; }
104}
105
106Geno::Geno(const char *genstring, char genformat, const char *genname, const char *comment)
107{
108        init(SString(genstring), genformat, SString(genname), SString(comment));
109}
110
111Geno::Geno(const SString& genstring, char genformat, const SString& genname, const SString& comment)
112{
113        init(genstring, genformat, genname, comment);
114}
115
116Geno::Geno(const Geno& src)
117:gen(src.gen), name(src.name), format(src.format), txt(src.txt), isvalid(src.isvalid),
118f0gen(0), mapinshift(src.mapinshift), mapoutshift(src.mapinshift),
119multiline(src.multiline), owner(0)
120{
121        f0gen = src.f0gen ? new Geno(*src.f0gen) : 0; refcount = 1;
122}
123
124void Geno::operator=(const Geno& src)
125{
126        freeF0();
127        gen = src.gen;
128        name = src.name;
129        format = src.format;
130        txt = src.txt;
131        isvalid = src.isvalid;
132        mapinshift = src.mapinshift;
133        mapoutshift = src.mapinshift;
134        multiline = src.multiline;
135        f0gen = src.f0gen ? new Geno(*src.f0gen) : 0;
136        owner = 0;
137}
138
139Geno::Geno(const SString& src)
140{
141        init(src, -1, SString::empty(), SString::empty());
142}
143
144void Geno::setGene(const SString& g, char newformat)
145{
146        gen = g;
147        isvalid = -1;
148        freeF0();
149        if (newformat >= 0) format = newformat;
150}
151
152void Geno::setString(const SString& g)
153{
154        freeF0();
155        init(g, -1, SString::empty(), SString::empty());
156}
157
158void Geno::setName(const SString& n)
159{
160        name = n;
161}
162
163void Geno::setComment(const SString& c)
164{
165        txt = c;
166}
167
168SString Geno::toString(void) const
169{
170        SString out;
171        int comment = 0;
172        if ((format != '1') || (comment = (txt.len() || name.len())))
173        {
174                if (multiline)
175                        out += "//";
176                else
177                        out += "/*";
178                out += format;
179                if (comment)
180                {
181                        if (txt.len()) { out += ";"; out += txt; }
182                        if (name.len()){ out += ";"; out += name; }
183                }
184                if (multiline)
185                        out += "\n";
186                else
187                        out += "*/";
188        }
189        out += gen;
190        return out;
191}
192
193SString Geno::shortString(void) const
194{
195        SString out;
196        if (format != '1')
197        {
198                if (multiline)
199                        out += "//";
200                else
201                        out += "/*";
202                if (format == 0)
203                        out += "invalid";
204                else
205                        out += format;
206                if (multiline)
207                        out += "\n";
208                else
209                        out += "*/";
210        }
211        out += gen;
212        return out;
213}
214
215int Geno::mapGenToString(int genpos) const
216{
217        if (genpos > gen.len()) return -2;
218        if (genpos<0) return -1;
219        return mapinshift + genpos;
220}
221
222int Geno::mapStringToGen(int stringpos) const
223{
224        stringpos -= mapinshift;
225        if (stringpos>gen.len()) return -2;
226        if (stringpos < 0) return -1;
227        return stringpos;
228}
229
230SString Geno::getGene(void) const { return gen; }
231SString Geno::getName(void) const { return name; }
232char Geno::getFormat(void) const { return format; }
233SString Geno::getComment(void) const { return txt; }
234
235int ModelGenoValidator::testGenoValidity(Geno& g)
236{
237        if (g.getFormat() == '0')
238        {
239                Model mod(g);
240                return mod.isValid();
241        }
242        else
243        {
244                bool converter_missing;
245                Geno f0geno = g.getConverted('0', NULL, &converter_missing);
246                if (converter_missing)
247                        return -1;//no result
248                return f0geno.isValid();
249        }
250}
251
252void Geno::validate()
253{
254        if (isvalid >= 0) return;
255        if (gen.len() == 0) { isvalid = 0; return; }
256        if (format == INVALID_FORMAT) { isvalid = 0; return; }
257        Validators* vals=getValidators();
258        if (vals!=NULL)
259                {
260#ifdef WARN_VALIDATION_INCONSISTENCY
261                vector<int> results;
262                int first_result=-1;
263                FOREACH(GenoValidator*, v, (*vals))
264                        {
265                        int r=v->testGenoValidity(*this);
266                        if (first_result<0) first_result=r;
267                        results.push_back(r);
268                        }
269                int N=vals->size();
270                for(int i=1;i<N;i++)
271                        if (results[i]!=results[0])
272                                {
273                                SString txt="Inconsistent validation results";
274                                for(int i=0;i<N;i++)
275                                        txt+=SString::sprintf(" %d",results[i]);
276                                txt+=" for genotype '";
277                                txt+=getGene();
278                                txt+="'";
279                                logPrintf("Geno","validate",LOG_WARN,txt.c_str());
280                                break;
281                                }
282                isvalid=first_result;
283                if (isvalid>=0)
284                        return;
285#else
286        FOREACH(GenoValidator*, v, (*vals))
287                if ((isvalid = v->testGenoValidity(*this)) >= 0)
288                        return;
289#endif
290                }
291        isvalid = 0;
292        logPrintf("Geno", "validate", LOG_WARN, "Wrong configuration? No genotype validators defined for genetic format 'f%c'.", format);
293}
294
295bool Geno::isValid(void)
296{
297        if (isvalid<0)
298                {
299                LoggerToMemory err(LoggerBase::Enable | LoggerToMemory::StoreAllMessages,LOG_INFO);
300                validate();
301                err.disable();
302                string msg=err.getCountSummary();
303                if (msg.size()>0)
304                        {
305                        msg+=ssprintf(" while checking validity of '%s'",getName().c_str());
306                        msg+="\n";
307                        msg+=err.getMessages();
308                        logMessage("Geno","isValid",err.getErrorLevel(),msg.c_str());
309                        }
310                }
311        return isvalid>0;
312}
313
314Geno Geno::getConverted(char otherformat, MultiMap *m, bool *converter_missing)
315{
316        if (otherformat == getFormat()) { if (converter_missing) *converter_missing = false; return *this; }
317#ifndef NO_GENOCONVMANAGER
318        GenoConvManager *converters=getConverters();
319        if (converters)
320        {
321                if ((otherformat == '0') && (!m))
322                {
323                        if (!f0gen)
324                                f0gen = new Geno(converters->convert(*this, otherformat, NULL, converter_missing));
325                        else
326                                { if (converter_missing) *converter_missing = false; }
327                        return *f0gen;
328                }
329                else
330                        return converters->convert(*this, otherformat, m, converter_missing);
331        }
332#endif
333        if (converter_missing) *converter_missing = true;
334        return (otherformat == getFormat()) ? *this : Geno(0, 0, 0, "GenConvManager not available");
335}
336
337Geno::~Geno()
338{
339        if (f0gen) delete f0gen;
340}
Note: See TracBrowser for help on using the repository browser.