~ubuntu-branches/ubuntu/saucy/3depict/saucy

« back to all changes in this revision

Viewing changes to src/filters/ionDownsample.cpp

  • Committer: Package Import Robot
  • Author(s): D Haley
  • Date: 2013-05-17 00:52:39 UTC
  • mfrom: (3.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20130517005239-7bl4mnhkvrhc2ba6
Tags: 0.0.13-1
Upload to unstable 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include "../APTClasses.h"
2
 
#include "../xmlHelper.h"
3
 
 
4
 
#include "../translation.h"
5
 
 
6
 
#include "ionDownsample.h"
7
 
 
8
 
enum
9
 
{
10
 
        KEY_IONDOWNSAMPLE_FRACTION=1,
11
 
        KEY_IONDOWNSAMPLE_FIXEDOUT,
12
 
        KEY_IONDOWNSAMPLE_COUNT,
13
 
        KEY_IONDOWNSAMPLE_PERSPECIES,
14
 
        KEY_IONDOWNSAMPLE_ENABLE,
15
 
        //Dynamic area for this filter class. May validly use any index after this value
16
 
        KEY_IONDOWNSAMPLE_DYNAMIC, 
17
 
};
18
 
 
19
 
//!Downsampling filter
20
 
enum
21
 
{
22
 
        IONDOWNSAMPLE_ABORT_ERR=1,
23
 
        IONDOWNSAMPLE_BAD_ALLOC,
24
 
};
25
 
 
26
 
 
27
 
// == Ion Downsampling filter ==
28
 
 
29
 
IonDownsampleFilter::IonDownsampleFilter()
30
 
{
31
 
        rng.initTimer();
32
 
        fixedNumOut=true;
33
 
        fraction=0.1f;
34
 
        maxAfterFilter=5000;
35
 
        rsdIncoming=0;
36
 
        perSpecies=false;
37
 
 
38
 
        cacheOK=false;
39
 
        cache=true; //By default, we should cache, but decision is made higher up
40
 
 
41
 
}
42
 
 
43
 
void IonDownsampleFilter::initFilter(const std::vector<const FilterStreamData *> &dataIn,
44
 
                                std::vector<const FilterStreamData *> &dataOut)
45
 
{
46
 
        const RangeStreamData *c=0;
47
 
        //Determine if we have an incoming range
48
 
        for (size_t i = 0; i < dataIn.size(); i++) 
49
 
        {
50
 
                if(dataIn[i]->getStreamType() == STREAM_TYPE_RANGE)
51
 
                {
52
 
                        c=(const RangeStreamData *)dataIn[i];
53
 
 
54
 
                        break;
55
 
                }
56
 
        }
57
 
 
58
 
        //we no longer (or never did) have any incoming ranges. Not much to do
59
 
        if(!c)
60
 
        {
61
 
                //delete the old incoming range pointer
62
 
                if(rsdIncoming)
63
 
                        delete rsdIncoming;
64
 
                rsdIncoming=0;
65
 
 
66
 
                //Well, don't use per-species info anymore
67
 
                perSpecies=false;
68
 
        }
69
 
        else
70
 
        {
71
 
 
72
 
 
73
 
                //If we didn't have a previously incoming rsd, then make one up!
74
 
                // - we can't use a reference, as the rangestreams are technically transient,
75
 
                // so we have to copy.
76
 
                if(!rsdIncoming)
77
 
                {
78
 
                        rsdIncoming = new RangeStreamData;
79
 
                        *rsdIncoming=*c;
80
 
 
81
 
                        if(ionFractions.size() != c->rangeFile->getNumIons())
82
 
                        {
83
 
                                //set up some defaults; seeded from normal
84
 
                                ionFractions.resize(c->rangeFile->getNumIons(),fraction);
85
 
                                ionLimits.resize(c->rangeFile->getNumIons(),maxAfterFilter);
86
 
                        }
87
 
                }
88
 
                else
89
 
                {
90
 
 
91
 
                        //OK, so we have a range incoming already (from last time)
92
 
                        //-- the question is, is it the same one we had before ?
93
 
                        //
94
 
                        //Do a pointer comparison (its a hack, yes, but it should work)
95
 
                        if(rsdIncoming->rangeFile != c->rangeFile)
96
 
                        {
97
 
                                //hmm, it is different. well, trash the old incoming rng
98
 
                                delete rsdIncoming;
99
 
 
100
 
                                rsdIncoming = new RangeStreamData;
101
 
                                *rsdIncoming=*c;
102
 
 
103
 
                                ionFractions.resize(c->rangeFile->getNumIons(),fraction);
104
 
                                ionLimits.resize(c->rangeFile->getNumIons(),maxAfterFilter);
105
 
                        }
106
 
                        else if(ionFractions.size() !=c->rangeFile->getNumIons())
107
 
                        {
108
 
                                //well its the same range, but somehow the number of ions 
109
 
                                //have changed. Could be range was reloaded.
110
 
                                ionFractions.resize(rsdIncoming->rangeFile->getNumIons(),fraction);
111
 
                                ionLimits.resize(rsdIncoming->rangeFile->getNumIons(),maxAfterFilter);
112
 
                        }
113
 
 
114
 
                        //Ensure what is enabled and is disabled is up-to-date  
115
 
                        for(unsigned int ui=0;ui<rsdIncoming->enabledRanges.size();ui++)
116
 
                                rsdIncoming->enabledRanges[ui] = c->enabledRanges[ui];
117
 
                        for(unsigned int ui=0;ui<rsdIncoming->enabledIons.size();ui++)
118
 
                                rsdIncoming->enabledIons[ui] = c->enabledIons[ui];
119
 
                                
120
 
                }
121
 
 
122
 
        }
123
 
 
124
 
 
125
 
        ASSERT(ionLimits.size() == ionFractions.size());
126
 
}
127
 
 
128
 
Filter *IonDownsampleFilter::cloneUncached() const
129
 
{
130
 
        IonDownsampleFilter *p=new IonDownsampleFilter();
131
 
        p->rng = rng;
132
 
        p->maxAfterFilter=maxAfterFilter;
133
 
        p->fraction=fraction;
134
 
        p->perSpecies=perSpecies;
135
 
        p->rsdIncoming=rsdIncoming;
136
 
 
137
 
        p->ionFractions.resize(ionFractions.size());
138
 
        std::copy(ionFractions.begin(),ionFractions.end(),p->ionFractions.begin());
139
 
        p->ionLimits.resize(ionLimits.size());
140
 
        std::copy(ionLimits.begin(),ionLimits.end(),p->ionLimits.begin());
141
 
 
142
 
 
143
 
        //We are copying wether to cache or not,
144
 
        //not the cache itself
145
 
        p->cache=cache;
146
 
        p->cacheOK=false;
147
 
        p->userString=userString;
148
 
        p->fixedNumOut=fixedNumOut;
149
 
        return p;
150
 
}
151
 
 
152
 
size_t IonDownsampleFilter::numBytesForCache(size_t nObjects) const
153
 
{
154
 
        if(fixedNumOut)
155
 
        {
156
 
                if(nObjects > maxAfterFilter)
157
 
                        return maxAfterFilter*IONDATA_SIZE;
158
 
                else
159
 
                        return nObjects*IONDATA_SIZE;
160
 
        }
161
 
        else
162
 
        {
163
 
                return (size_t)((float)(nObjects*IONDATA_SIZE)*fraction);
164
 
        }
165
 
}
166
 
 
167
 
unsigned int IonDownsampleFilter::refresh(const std::vector<const FilterStreamData *> &dataIn,
168
 
        std::vector<const FilterStreamData *> &getOut, ProgressData &progress, bool (*callback)(bool))
169
 
{
170
 
        //use the cached copy if we have it.
171
 
        if(cacheOK)
172
 
        {
173
 
                for(size_t ui=0;ui<dataIn.size();ui++)
174
 
                {
175
 
                        if(dataIn[ui]->getStreamType() != STREAM_TYPE_IONS)
176
 
                                getOut.push_back(dataIn[ui]);
177
 
                }
178
 
                for(size_t ui=0;ui<filterOutputs.size();ui++)
179
 
                        getOut.push_back(filterOutputs[ui]);
180
 
                return 0;
181
 
        }
182
 
 
183
 
 
184
 
        size_t totalSize = numElements(dataIn,STREAM_TYPE_IONS);
185
 
        if(!perSpecies) 
186
 
        {
187
 
                for(size_t ui=0;ui<dataIn.size() ;ui++)
188
 
                {
189
 
                        switch(dataIn[ui]->getStreamType())
190
 
                        {
191
 
                                case STREAM_TYPE_IONS: 
192
 
                                {
193
 
                                        if(!totalSize)
194
 
                                                continue;
195
 
 
196
 
                                        IonStreamData *d;
197
 
                                        d=new IonStreamData;
198
 
                                        d->parent=this;
199
 
                                        try
200
 
                                        {
201
 
                                                if(fixedNumOut)
202
 
                                                {
203
 
                                                        float frac;
204
 
                                                        frac = (float)(((const IonStreamData*)dataIn[ui])->data.size())/(float)totalSize;
205
 
 
206
 
                                                        randomSelect(d->data,((const IonStreamData *)dataIn[ui])->data,
207
 
                                                                                rng,maxAfterFilter*frac,progress.filterProgress,callback,strongRandom);
208
 
 
209
 
 
210
 
                                                }
211
 
                                                else
212
 
                                                {
213
 
 
214
 
                                                        unsigned int curProg=NUM_CALLBACK;
215
 
                                                        size_t n=0;
216
 
                                                        //Reserve 90% of storage needed.
217
 
                                                        //highly likely with even modest numbers of ions
218
 
                                                        //that this will be exceeeded
219
 
                                                        d->data.reserve(fraction*0.9*totalSize);
220
 
 
221
 
                                                        ASSERT(dataIn[ui]->getStreamType() == STREAM_TYPE_IONS);
222
 
 
223
 
                                                        for(vector<IonHit>::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin();
224
 
                                                                       it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it)
225
 
                                                        {
226
 
                                                                if(rng.genUniformDev() <  fraction)
227
 
                                                                        d->data.push_back(*it);
228
 
                                                        
229
 
                                                                //update progress every CALLBACK ions
230
 
                                                                if(!curProg--)
231
 
                                                                {
232
 
                                                                        curProg=NUM_CALLBACK;
233
 
                                                                        n+=NUM_CALLBACK;
234
 
                                                                        progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
235
 
                                                                        if(!(*callback)(false))
236
 
                                                                        {
237
 
                                                                                delete d;
238
 
                                                                                return IONDOWNSAMPLE_ABORT_ERR;
239
 
                                                                        }
240
 
                                                                }
241
 
                                                        }
242
 
                                                }
243
 
                                        }
244
 
                                        catch(std::bad_alloc)
245
 
                                        {
246
 
                                                delete d;
247
 
                                                return IONDOWNSAMPLE_BAD_ALLOC;
248
 
                                        }
249
 
 
250
 
 
251
 
                                        //Copy over other attributes
252
 
                                        d->r = ((IonStreamData *)dataIn[ui])->r;
253
 
                                        d->g = ((IonStreamData *)dataIn[ui])->g;
254
 
                                        d->b =((IonStreamData *)dataIn[ui])->b;
255
 
                                        d->a =((IonStreamData *)dataIn[ui])->a;
256
 
                                        d->ionSize =((IonStreamData *)dataIn[ui])->ionSize;
257
 
                                        d->representationType=((IonStreamData *)dataIn[ui])->representationType;
258
 
                                        d->valueType=((IonStreamData *)dataIn[ui])->valueType;
259
 
 
260
 
                                        //getOut is const, so shouldn't be modified
261
 
                                        if(cache)
262
 
                                        {
263
 
                                                d->cached=1;
264
 
                                                filterOutputs.push_back(d);
265
 
                                                cacheOK=true;
266
 
                                        }
267
 
                                        else
268
 
                                                d->cached=0;
269
 
                        
270
 
 
271
 
                                        getOut.push_back(d);
272
 
                                        break;
273
 
                                }
274
 
                        
275
 
                                default:
276
 
                                        getOut.push_back(dataIn[ui]);
277
 
                                        break;
278
 
                        }
279
 
 
280
 
                }
281
 
        }
282
 
        else
283
 
        {
284
 
                ASSERT(rsdIncoming);
285
 
                const IonStreamData *input;
286
 
 
287
 
                //Construct two vectors. One with the ion IDs for each input
288
 
                //ion stream. the other with the total number of ions in the input
289
 
                //for each ion type 
290
 
                vector<size_t> numIons,ionIDVec;
291
 
                numIons.resize(rsdIncoming->rangeFile->getNumIons(),0);
292
 
 
293
 
                for(unsigned int uj=0;uj<dataIn.size() ;uj++)
294
 
                {
295
 
                        if(dataIn[uj]->getStreamType() == STREAM_TYPE_IONS)
296
 
                        {
297
 
                                input=(const IonStreamData*)dataIn[uj];
298
 
                                if(input->data.size())
299
 
                                {
300
 
                                        unsigned int ionID;
301
 
                                        ionID=rsdIncoming->rangeFile->getIonID(
302
 
                                                input->data[0].getMassToCharge()); 
303
 
 
304
 
                                        if(ionID != (unsigned int)-1)
305
 
                                                numIons[ionID]+=input->data.size();
306
 
                                        
307
 
                                        ionIDVec.push_back(ionID);
308
 
                                }
309
 
                        }
310
 
                }
311
 
 
312
 
                size_t n=0;
313
 
                unsigned int idPos=0;
314
 
                for(size_t ui=0;ui<dataIn.size() ;ui++)
315
 
                {
316
 
                        switch(dataIn[ui]->getStreamType())
317
 
                        {
318
 
                                case STREAM_TYPE_IONS: 
319
 
                                {
320
 
                                        input=(const IonStreamData*)dataIn[ui];
321
 
                        
322
 
                                        //Don't process ionstreams that are empty       
323
 
                                        if(!input->data.size())
324
 
                                                continue;
325
 
 
326
 
                                        //FIXME: Allow processing of unranged data
327
 
                                        //Don't process streams that are not ranged, as we cannot get their desired fractions
328
 
                                        //at this time
329
 
                                        if(ionIDVec[idPos]==(unsigned int)-1)
330
 
                                                continue;
331
 
 
332
 
                                        IonStreamData *d;
333
 
                                        d=new IonStreamData;
334
 
                                        d->parent=this;
335
 
                                        try
336
 
                                        {
337
 
                                                if(fixedNumOut)
338
 
                                                {
339
 
                                                        //if we are building the fixed number for output,
340
 
                                                        //then compute the relative fraction for this ion set
341
 
                                                        float frac;
342
 
                                                        frac = (float)(input->data.size())/(float)(numIons[ionIDVec[idPos]]);
343
 
 
344
 
                                                        //The total number of ions is the specified value for this ionID, multiplied by
345
 
                                                        //this stream's fraction of the total incoming data
346
 
                                                        randomSelect(d->data,input->data, rng,frac*ionLimits[ionIDVec[idPos]],
347
 
                                                                        progress.filterProgress,callback,strongRandom);
348
 
                                                }
349
 
                                                else
350
 
                                                {
351
 
                                                        //Use the direct fractions as entered in by user. 
352
 
 
353
 
                                                        unsigned int curProg=NUM_CALLBACK;
354
 
 
355
 
                                                        float thisFraction = ionFractions[ionIDVec[idPos]];
356
 
                                                        
357
 
                                                        //Reserve 90% of storage needed.
358
 
                                                        //highly likely (poisson) with even modest numbers of ions
359
 
                                                        //that this will be exceeeded, and thus we won't over-allocate
360
 
                                                        d->data.reserve(thisFraction*0.9*numIons[ionIDVec[idPos]]);
361
 
 
362
 
                                                        if(thisFraction)
363
 
                                                        {
364
 
                                                                for(vector<IonHit>::const_iterator it=input->data.begin();
365
 
                                                                               it!=input->data.end(); ++it)
366
 
                                                                {
367
 
                                                                        if(rng.genUniformDev() <  thisFraction)
368
 
                                                                                d->data.push_back(*it);
369
 
                                                                
370
 
                                                                        //update progress every CALLBACK ions
371
 
                                                                        if(!curProg--)
372
 
                                                                        {
373
 
                                                                                n+=NUM_CALLBACK;
374
 
                                                                                progress.filterProgress= 
375
 
                                                                                        (unsigned int)((float)(n)/((float)totalSize)*100.0f);
376
 
                                                                                if(!(*callback)(false))
377
 
                                                                                {
378
 
                                                                                        delete d;
379
 
                                                                                        return IONDOWNSAMPLE_ABORT_ERR;
380
 
                                                                                }
381
 
                                                                        }
382
 
                                                                }
383
 
                                                
384
 
                                                        }
385
 
                                                }
386
 
                                        }
387
 
                                        catch(std::bad_alloc)
388
 
                                        {
389
 
                                                delete d;
390
 
                                                return IONDOWNSAMPLE_BAD_ALLOC;
391
 
                                        }
392
 
 
393
 
 
394
 
                                        if(d->data.size())
395
 
                                        {
396
 
                                                //Copy over other attributes
397
 
                                                d->r = input->r;
398
 
                                                d->g = input->g;
399
 
                                                d->b =input->b;
400
 
                                                d->a =input->a;
401
 
                                                d->ionSize =input->ionSize;
402
 
                                                d->representationType=input->representationType;
403
 
                                                d->valueType=input->valueType;
404
 
 
405
 
 
406
 
                                                //getOut is const, so shouldn't be modified
407
 
                                                if(cache)
408
 
                                                {
409
 
                                                        d->cached=1;
410
 
                                                        filterOutputs.push_back(d);
411
 
                                                        cacheOK=true;
412
 
                                                }
413
 
                                                else
414
 
                                                        d->cached=0;
415
 
                        
416
 
 
417
 
                                                getOut.push_back(d);
418
 
                                        }
419
 
                                        else
420
 
                                                delete d;
421
 
                                        //next ion
422
 
                                        idPos++;
423
 
                                        
424
 
                                        break;
425
 
                                }
426
 
                        
427
 
                                default:
428
 
                                        getOut.push_back(dataIn[ui]);
429
 
                                        break;
430
 
                        }
431
 
 
432
 
                }
433
 
 
434
 
 
435
 
        }       
436
 
 
437
 
        return 0;
438
 
}
439
 
 
440
 
 
441
 
void IonDownsampleFilter::getProperties(FilterProperties &propertyList) const
442
 
{
443
 
        propertyList.data.clear();
444
 
        propertyList.keys.clear();
445
 
        propertyList.types.clear();
446
 
 
447
 
        vector<unsigned int> type,keys;
448
 
        vector<pair<string,string> > s;
449
 
 
450
 
        string tmpStr;
451
 
        stream_cast(tmpStr,fixedNumOut);
452
 
        s.push_back(std::make_pair(TRANS("By Count"), tmpStr));
453
 
        keys.push_back(KEY_IONDOWNSAMPLE_FIXEDOUT);
454
 
        type.push_back(PROPERTY_TYPE_BOOL);
455
 
 
456
 
        if(rsdIncoming)
457
 
        {
458
 
                stream_cast(tmpStr,perSpecies);
459
 
                s.push_back(std::make_pair(TRANS("Per Species"), tmpStr));
460
 
                keys.push_back(KEY_IONDOWNSAMPLE_PERSPECIES);
461
 
                type.push_back(PROPERTY_TYPE_BOOL);
462
 
        }       
463
 
 
464
 
 
465
 
        propertyList.data.push_back(s);
466
 
        propertyList.types.push_back(type);
467
 
        propertyList.keys.push_back(keys);
468
 
 
469
 
        //Start a new section
470
 
        s.clear();
471
 
        type.clear();
472
 
        keys.clear();
473
 
 
474
 
        if(rsdIncoming && perSpecies)
475
 
        {
476
 
                unsigned int typeVal;
477
 
                if(fixedNumOut)
478
 
                        typeVal=PROPERTY_TYPE_INTEGER;
479
 
                else
480
 
                        typeVal=PROPERTY_TYPE_REAL;
481
 
 
482
 
                //create a  single line for each
483
 
                for(unsigned  int ui=0; ui<rsdIncoming->enabledIons.size(); ui++)
484
 
                {
485
 
                        if(rsdIncoming->enabledIons[ui])
486
 
                        {
487
 
                                if(fixedNumOut)
488
 
                                        stream_cast(tmpStr,ionLimits[ui]);
489
 
                                else
490
 
                                        stream_cast(tmpStr,ionFractions[ui]);
491
 
 
492
 
                                s.push_back(make_pair(
493
 
                                        rsdIncoming->rangeFile->getName(ui), tmpStr));
494
 
                                type.push_back(typeVal);
495
 
                                keys.push_back(KEY_IONDOWNSAMPLE_DYNAMIC+ui);
496
 
                        }
497
 
                }
498
 
        }
499
 
        else
500
 
        {
501
 
                if(fixedNumOut)
502
 
                {
503
 
                        stream_cast(tmpStr,maxAfterFilter);
504
 
                        keys.push_back(KEY_IONDOWNSAMPLE_COUNT);
505
 
                        s.push_back(make_pair(TRANS("Output Count"), tmpStr));
506
 
                        type.push_back(PROPERTY_TYPE_INTEGER);
507
 
                }
508
 
                else
509
 
                {
510
 
                        stream_cast(tmpStr,fraction);
511
 
                        s.push_back(make_pair(TRANS("Out Fraction"), tmpStr));
512
 
                        keys.push_back(KEY_IONDOWNSAMPLE_FRACTION);
513
 
                        type.push_back(PROPERTY_TYPE_REAL);
514
 
 
515
 
 
516
 
                }
517
 
        }
518
 
        propertyList.data.push_back(s);
519
 
        propertyList.types.push_back(type);
520
 
        propertyList.keys.push_back(keys);
521
 
}
522
 
 
523
 
bool IonDownsampleFilter::setProperty( unsigned int set, unsigned int key,
524
 
                                        const std::string &value, bool &needUpdate)
525
 
{
526
 
        needUpdate=false;
527
 
        switch(key)
528
 
        {
529
 
                case KEY_IONDOWNSAMPLE_FIXEDOUT: 
530
 
                {
531
 
                        string stripped=stripWhite(value);
532
 
 
533
 
                        if(!(stripped == "1"|| stripped == "0"))
534
 
                                return false;
535
 
 
536
 
                        bool lastVal=fixedNumOut;
537
 
                        if(stripped=="1")
538
 
                                fixedNumOut=true;
539
 
                        else
540
 
                                fixedNumOut=false;
541
 
 
542
 
                        //if the result is different, the
543
 
                        //cache should be invalidated
544
 
                        if(lastVal!=fixedNumOut)
545
 
                        {
546
 
                                needUpdate=true;
547
 
                                clearCache();
548
 
                        }
549
 
 
550
 
                        break;
551
 
                }       
552
 
                case KEY_IONDOWNSAMPLE_FRACTION:
553
 
                {
554
 
                        float newFraction;
555
 
                        if(stream_cast(newFraction,value))
556
 
                                return false;
557
 
 
558
 
                        if(newFraction < 0.0f || newFraction > 1.0f)
559
 
                                return false;
560
 
 
561
 
                        //In the case of fixed number output, 
562
 
                        //our cache is invalidated
563
 
                        if(!fixedNumOut)
564
 
                        {
565
 
                                needUpdate=true;
566
 
                                clearCache();
567
 
                        }
568
 
 
569
 
                        fraction=newFraction;
570
 
                        
571
 
 
572
 
                        break;
573
 
                }
574
 
                case KEY_IONDOWNSAMPLE_COUNT:
575
 
                {
576
 
                        size_t count;
577
 
 
578
 
                        if(stream_cast(count,value))
579
 
                                return false;
580
 
 
581
 
                        maxAfterFilter=count;
582
 
                        //In the case of fixed number output, 
583
 
                        //our cache is invalidated
584
 
                        if(fixedNumOut)
585
 
                        {
586
 
                                needUpdate=true;
587
 
                                clearCache();
588
 
                        }
589
 
                        
590
 
                        break;
591
 
                }       
592
 
                case KEY_IONDOWNSAMPLE_PERSPECIES: 
593
 
                {
594
 
                        string stripped=stripWhite(value);
595
 
 
596
 
                        if(!(stripped == "1"|| stripped == "0"))
597
 
                                return false;
598
 
 
599
 
                        bool lastVal=perSpecies;
600
 
                        if(stripped=="1")
601
 
                                perSpecies=true;
602
 
                        else
603
 
                                perSpecies=false;
604
 
 
605
 
                        //if the result is different, the
606
 
                        //cache should be invalidated
607
 
                        if(lastVal!=perSpecies)
608
 
                        {
609
 
                                needUpdate=true;
610
 
                                clearCache();
611
 
                        }
612
 
 
613
 
                        break;
614
 
                }       
615
 
                default:
616
 
                {
617
 
                        ASSERT(rsdIncoming);
618
 
                        ASSERT(key >=KEY_IONDOWNSAMPLE_DYNAMIC);
619
 
                        ASSERT(key < KEY_IONDOWNSAMPLE_DYNAMIC+ionLimits.size());
620
 
                        ASSERT(ionLimits.size() == ionFractions.size());
621
 
 
622
 
                        unsigned int offset;
623
 
                        offset=key-KEY_IONDOWNSAMPLE_DYNAMIC;
624
 
 
625
 
                        //Dynamically generated list of downsamples
626
 
                        if(fixedNumOut)
627
 
                        {
628
 
                                //Fixed count
629
 
                                size_t v;
630
 
                                if(stream_cast(v,value))
631
 
                                        return false;
632
 
                                ionLimits[offset]=v;
633
 
                        }
634
 
                        else
635
 
                        {
636
 
                                //Fixed fraction
637
 
                                float v;
638
 
                                if(stream_cast(v,value))
639
 
                                        return false;
640
 
 
641
 
                                if(v < 0.0f || v> 1.0f)
642
 
                                        return false;
643
 
 
644
 
                                ionFractions[offset]=v;
645
 
                        }
646
 
                        
647
 
                        needUpdate=true;
648
 
                        clearCache();
649
 
                        break;
650
 
                }
651
 
 
652
 
        }       
653
 
        return true;
654
 
}
655
 
 
656
 
 
657
 
std::string  IonDownsampleFilter::getErrString(unsigned int code) const
658
 
{
659
 
        switch(code)
660
 
        {
661
 
                case IONDOWNSAMPLE_ABORT_ERR:
662
 
                        return std::string(TRANS("Downsample Aborted"));
663
 
                case IONDOWNSAMPLE_BAD_ALLOC:
664
 
                        return std::string(TRANS("Insuffient memory for downsample"));
665
 
        }       
666
 
 
667
 
        return std::string("BUG! Should not see this (IonDownsample)");
668
 
}
669
 
 
670
 
bool IonDownsampleFilter::writeState(std::ofstream &f,unsigned int format, unsigned int depth) const
671
 
{
672
 
        using std::endl;
673
 
        switch(format)
674
 
        {
675
 
                case STATE_FORMAT_XML:
676
 
                {       
677
 
                        f << tabs(depth) <<  "<" << trueName() << ">" << endl;
678
 
                        f << tabs(depth+1) << "<userstring value=\""<< escapeXML(userString) << "\"/>"  << endl;
679
 
 
680
 
                        f << tabs(depth+1) << "<fixednumout value=\""<<fixedNumOut<< "\"/>"  << endl;
681
 
                        f << tabs(depth+1) << "<fraction value=\""<<fraction<< "\"/>"  << endl;
682
 
                        f << tabs(depth+1) << "<maxafterfilter value=\"" << maxAfterFilter << "\"/>" << endl;
683
 
                        f << tabs(depth+1) << "<perspecies value=\""<<perSpecies<< "\"/>"  << endl;
684
 
                        f << tabs(depth+1) << "<fractions>" << endl;
685
 
                        for(unsigned int ui=0;ui<ionFractions.size(); ui++) 
686
 
                                f << tabs(depth+2) << "<scalar value=\"" << ionFractions[ui] << "\"/>" << endl; 
687
 
                        f << tabs(depth+1) << "</fractions>" << endl;
688
 
                        f << tabs(depth+1) << "<limits>" << endl;
689
 
                        for(unsigned int ui=0;ui<ionLimits.size(); ui++)
690
 
                                f << tabs(depth+2) << "<scalar value=\"" << ionLimits[ui] << "\"/>" << endl; 
691
 
                        f << tabs(depth+1) << "</limits>" << endl;
692
 
                        f << tabs(depth) << "</" <<trueName()<< ">" << endl;
693
 
                        break;
694
 
                }
695
 
                default:
696
 
                        ASSERT(false);
697
 
                        return false;
698
 
        }
699
 
 
700
 
        return true;
701
 
}
702
 
 
703
 
bool IonDownsampleFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileDir)
704
 
{
705
 
        using std::string;
706
 
        string tmpStr;
707
 
 
708
 
        xmlChar *xmlString;
709
 
        //Retrieve user string
710
 
        if(XMLHelpFwdToElem(nodePtr,"userstring"))
711
 
                return false;
712
 
 
713
 
        xmlString=xmlGetProp(nodePtr,(const xmlChar *)"value");
714
 
        if(!xmlString)
715
 
                return false;
716
 
        userString=(char *)xmlString;
717
 
        xmlFree(xmlString);
718
 
 
719
 
        //Retrieve number out (yes/no) mode
720
 
        if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixednumout","value"))
721
 
                return false;
722
 
        
723
 
        if(tmpStr == "1") 
724
 
                fixedNumOut=true;
725
 
        else if(tmpStr== "0")
726
 
                fixedNumOut=false;
727
 
        else
728
 
                return false;
729
 
        //===
730
 
                
731
 
        //Retrieve Fraction
732
 
        //===
733
 
        if(!XMLGetNextElemAttrib(nodePtr,fraction,"fraction","value"))
734
 
                return false;
735
 
        //disallow negative or values gt 1.
736
 
        if(fraction < 0.0f || fraction > 1.0f)
737
 
                return false;
738
 
        //===
739
 
        
740
 
        
741
 
        //Retrieve "perspecies" attrib
742
 
        if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"perspecies","value"))
743
 
                return false;
744
 
        
745
 
        if(tmpStr == "1") 
746
 
                perSpecies=true;
747
 
        else if(tmpStr== "0")
748
 
                perSpecies=false;
749
 
        else
750
 
                return false;
751
 
 
752
 
        xmlNodePtr lastNode;
753
 
        lastNode=nodePtr;
754
 
        //Retrieve the ion per-species fractions
755
 
        if(XMLHelpFwdToElem(nodePtr,"fractions"))
756
 
                return false;
757
 
 
758
 
        nodePtr=nodePtr->xmlChildrenNode;
759
 
 
760
 
        //Populate the ion fraction vector
761
 
        float fracThis; 
762
 
        while(XMLGetNextElemAttrib(nodePtr,fracThis,"scalar","value"))
763
 
                ionFractions.push_back(fracThis);
764
 
 
765
 
        
766
 
        nodePtr=lastNode;
767
 
 
768
 
        //Retrieve the ion per-species fractions
769
 
        if(XMLHelpFwdToElem(nodePtr,"limits"))
770
 
                return false;
771
 
 
772
 
        nodePtr=nodePtr->xmlChildrenNode;
773
 
        size_t limitThis;       
774
 
        while(XMLGetNextElemAttrib(nodePtr,limitThis,"scalar","value"))
775
 
                ionLimits.push_back(limitThis);
776
 
 
777
 
        if(ionLimits.size()!=ionFractions.size())
778
 
                return false;
779
 
 
780
 
        return true;
781
 
}
782
 
 
783
 
 
784
 
unsigned int IonDownsampleFilter::getRefreshBlockMask() const
785
 
{
786
 
        return STREAM_TYPE_IONS ;
787
 
}
788
 
 
789
 
unsigned int IonDownsampleFilter::getRefreshEmitMask() const
790
 
{
791
 
        return  STREAM_TYPE_IONS;
792
 
}
793
 
 
794
 
//----------
795
 
 
796
 
 
797
 
//Unit testing for this class
798
 
///-----
799
 
#ifdef DEBUG
800
 
 
801
 
//Create a synthetic dataset of points
802
 
// returned pointer *must* be deleted. Span must have 3 elements, and for best results sould be co-prime with one another; eg all prime numbers
803
 
IonStreamData *synthDataPts(unsigned int span[],unsigned int numPts);
804
 
 
805
 
//Test for fixed number of output ions
806
 
bool fixedSampleTest();
807
 
 
808
 
//Test for variable number of output ions
809
 
bool variableSampleTest();
810
 
 
811
 
//Unit tests
812
 
bool IonDownsampleFilter::runUnitTests()
813
 
{
814
 
        if(!fixedSampleTest())
815
 
                return false;
816
 
 
817
 
        if(!variableSampleTest())
818
 
                return false;
819
 
        
820
 
        return true;
821
 
}
822
 
 
823
 
bool fixedSampleTest()
824
 
{
825
 
        //Simulate some data to send to the filter
826
 
        vector<const FilterStreamData*> streamIn,streamOut;
827
 
        IonStreamData *d= new IonStreamData;
828
 
 
829
 
        const unsigned int NUM_PTS=10000;
830
 
        for(unsigned int ui=0;ui<NUM_PTS;ui++)
831
 
        {
832
 
                IonHit h;
833
 
                h.setPos(Point3D(ui,ui,ui));
834
 
                h.setMassToCharge(ui);
835
 
                d->data.push_back(h);
836
 
        }
837
 
 
838
 
 
839
 
        streamIn.push_back(d);
840
 
        //Set up the filter itself
841
 
        IonDownsampleFilter *f=new IonDownsampleFilter;
842
 
        f->setCaching(false);
843
 
 
844
 
        bool needUp;
845
 
        string s;
846
 
        unsigned int numOutput=NUM_PTS/10;
847
 
        
848
 
        f->setProperty(0,KEY_IONDOWNSAMPLE_FIXEDOUT,"1",needUp);
849
 
        stream_cast(s,numOutput);
850
 
        f->setProperty(0,KEY_IONDOWNSAMPLE_COUNT,s,needUp);
851
 
 
852
 
        //Do the refresh
853
 
        ProgressData p;
854
 
        f->refresh(streamIn,streamOut,p,dummyCallback);
855
 
 
856
 
        delete f;
857
 
        delete d;
858
 
 
859
 
        //Pass some tests
860
 
        TEST(streamOut.size() == 1, "Stream count");
861
 
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS, "stream type");
862
 
        TEST(streamOut[0]->getNumBasicObjects() == numOutput, "output ions (basicobject)"); 
863
 
        TEST( ((IonStreamData*)streamOut[0])->data.size() == numOutput, "output ions (direct)")
864
 
 
865
 
        delete streamOut[0];
866
 
        
867
 
        return true;
868
 
}
869
 
 
870
 
bool variableSampleTest()
871
 
{
872
 
        //Build some points to pass to the filter
873
 
        vector<const FilterStreamData*> streamIn,streamOut;
874
 
        
875
 
        unsigned int span[]={ 
876
 
                        5, 7, 9
877
 
                        };      
878
 
        const unsigned int NUM_PTS=10000;
879
 
        IonStreamData *d=synthDataPts(span,NUM_PTS);
880
 
 
881
 
        streamIn.push_back(d);
882
 
        IonDownsampleFilter *f=new IonDownsampleFilter;
883
 
        f->setCaching(false);   
884
 
        
885
 
        bool needUp;
886
 
        f->setProperty(0,KEY_IONDOWNSAMPLE_FIXEDOUT,"0",needUp);
887
 
        f->setProperty(0,KEY_IONDOWNSAMPLE_FRACTION,"0.1",needUp);
888
 
 
889
 
        //Do the refresh
890
 
        ProgressData p;
891
 
        TEST(!(f->refresh(streamIn,streamOut,p,dummyCallback)),"refresh error code");
892
 
 
893
 
        delete f;
894
 
        delete d;
895
 
 
896
 
 
897
 
        TEST(streamOut.size() == 1,"stream count");
898
 
        TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
899
 
 
900
 
        //It is HIGHLY improbable that it will be <1/10th of the requested number
901
 
        TEST(streamOut[0]->getNumBasicObjects() > 0.01*NUM_PTS 
902
 
                && streamOut[0]->getNumBasicObjects() <= NUM_PTS,"ion fraction");
903
 
 
904
 
        delete streamOut[0];
905
 
 
906
 
 
907
 
        return true;
908
 
}
909
 
 
910
 
IonStreamData *synthDataPts(unsigned int span[], unsigned int numPts)
911
 
{
912
 
        IonStreamData *d = new IonStreamData;
913
 
        
914
 
        for(unsigned int ui=0;ui<numPts;ui++)
915
 
        {
916
 
                IonHit h;
917
 
                h.setPos(Point3D(ui%span[0],
918
 
                        ui%span[1],ui%span[2]));
919
 
                h.setMassToCharge(ui);
920
 
                d->data.push_back(h);
921
 
        }
922
 
 
923
 
        return d;
924
 
}
925
 
 
926
 
#endif
927
 
///-----
928