1 /***************************************************************************
2  *                                                                         *
3  *   copyright : (C) 2007 The University of Toronto                        *
4  *                   netterfield@astro.utoronto.ca                         *
5  *   copyright : (C) 2005  University of British Columbia                  *
6  *                   dscott@phas.ubc.ca                                    *
7  *                                                                         *
8  *   This program is free software; you can redistribute it and/or modify  *
9  *   it under the terms of the GNU General Public License as published by  *
10  *   the Free Software Foundation; either version 2 of the License, or     *
11  *   (at your option) any later version.                                   *
12  *                                                                         *
13  ***************************************************************************/
14 
15 /* bin Y values into N bins from X min to X max, according to their X values.
16    This is like a 1D map, where X specifices the pixel the data go into. */
17 
18 #include "syncbin.h"
19 #include "objectstore.h"
20 #include "ui_syncbinconfig.h"
21 
22 // macros to find the top, bottom, and middle of a bin
23 #define BINMID(x) XMin+(XMax-XMin)*(double(x)+0.5)/double(nbins)
24 
25 #define BIN( x ) int(double(nbins)*(x-XMin)/(XMax-XMin))
26 
27 static const QString& VECTOR_IN_X = "Vector In X";
28 static const QString& VECTOR_IN_Y = "Vector In Y";
29 static const QString& SCALAR_IN_BINS = "Number of Bins";
30 static const QString& SCALAR_IN_XMIN = "X Min";
31 static const QString& SCALAR_IN_XMAX = "X Max";
32 
33 static const QString& VECTOR_OUT_X_OUT = "X out";
34 static const QString& VECTOR_OUT_Y_OUT = "Y out";
35 static const QString& VECTOR_OUT_Y_ERROR = "Y error";
36 static const QString& VECTOR_OUT_N = "N";
37 
38 class ConfigSyncBinPlugin : public Kst::DataObjectConfigWidget, public Ui_SyncBinConfig {
39   public:
ConfigSyncBinPlugin(QSettings * cfg)40     ConfigSyncBinPlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_SyncBinConfig() {
41       _store = 0;
42       setupUi(this);
43     }
44 
~ConfigSyncBinPlugin()45     ~ConfigSyncBinPlugin() {}
46 
setObjectStore(Kst::ObjectStore * store)47     void setObjectStore(Kst::ObjectStore* store) {
48       _store = store;
49       _vectorX->setObjectStore(store);
50       _vectorY->setObjectStore(store);
51       _scalarBins->setObjectStore(store);
52       _scalarXMin->setObjectStore(store);
53       _scalarXMax->setObjectStore(store);
54       _scalarBins->setDefaultValue(0);
55       _scalarXMin->setDefaultValue(0);
56       _scalarXMax->setDefaultValue(0);
57     }
58 
setupSlots(QWidget * dialog)59     void setupSlots(QWidget* dialog) {
60       if (dialog) {
61         connect(_vectorX, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
62         connect(_vectorY, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
63         connect(_scalarBins, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
64         connect(_scalarXMin, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
65         connect(_scalarXMax, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
66       }
67     }
68 
selectedVectorX()69     Kst::VectorPtr selectedVectorX() { return _vectorX->selectedVector(); };
setSelectedVectorX(Kst::VectorPtr vector)70     void setSelectedVectorX(Kst::VectorPtr vector) { return _vectorX->setSelectedVector(vector); };
71 
selectedVectorY()72     Kst::VectorPtr selectedVectorY() { return _vectorY->selectedVector(); };
setSelectedVectorY(Kst::VectorPtr vector)73     void setSelectedVectorY(Kst::VectorPtr vector) { return _vectorY->setSelectedVector(vector); };
74 
selectedScalarBins()75     Kst::ScalarPtr selectedScalarBins() { return _scalarBins->selectedScalar(); };
setSelectedScalarBins(Kst::ScalarPtr scalar)76     void setSelectedScalarBins(Kst::ScalarPtr scalar) { return _scalarBins->setSelectedScalar(scalar); };
77 
selectedScalarXMin()78     Kst::ScalarPtr selectedScalarXMin() { return _scalarXMin->selectedScalar(); };
setSelectedScalarXMin(Kst::ScalarPtr scalar)79     void setSelectedScalarXMin(Kst::ScalarPtr scalar) { return _scalarXMin->setSelectedScalar(scalar); };
80 
selectedScalarXMax()81     Kst::ScalarPtr selectedScalarXMax() { return _scalarXMax->selectedScalar(); };
setSelectedScalarXMax(Kst::ScalarPtr scalar)82     void setSelectedScalarXMax(Kst::ScalarPtr scalar) { return _scalarXMax->setSelectedScalar(scalar); };
83 
84 
setupFromObject(Kst::Object * dataObject)85     virtual void setupFromObject(Kst::Object* dataObject) {
86       if (SyncBinSource* source = static_cast<SyncBinSource*>(dataObject)) {
87         setSelectedVectorX(source->vectorX());
88         setSelectedVectorY(source->vectorY());
89         setSelectedScalarBins(source->scalarBins());
90         setSelectedScalarXMin(source->scalarXMin());
91         setSelectedScalarXMax(source->scalarXMax());
92       }
93     }
94 
configurePropertiesFromXml(Kst::ObjectStore * store,QXmlStreamAttributes & attrs)95     virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) {
96       Q_UNUSED(store);
97       Q_UNUSED(attrs);
98 
99       bool validTag = true;
100 
101 //       QStringRef av;
102 //       av = attrs.value("value");
103 //       if (!av.isNull()) {
104 //         _configValue = QVariant(av.toString()).toBool();
105 //       }
106 
107       return validTag;
108     }
109 
110   public slots:
save()111     virtual void save() {
112       if (_cfg) {
113         _cfg->beginGroup("SyncBin DataObject Plugin");
114         _cfg->setValue("Input Vector X", _vectorX->selectedVector()->Name());
115         _cfg->setValue("Input Vector Y", _vectorY->selectedVector()->Name());
116         _cfg->setValue("Input Scalar Number of Bins", _scalarBins->selectedScalar()->Name());
117         _cfg->setValue("Input Scalar X Min", _scalarXMin->selectedScalar()->Name());
118         _cfg->setValue("Input Scalar X Max", _scalarXMax->selectedScalar()->Name());
119         _cfg->endGroup();
120       }
121     }
122 
load()123     virtual void load() {
124       if (_cfg && _store) {
125         _cfg->beginGroup("SyncBin DataObject Plugin");
126         QString vectorName = _cfg->value("Input Vector X").toString();
127         Kst::Object* object = _store->retrieveObject(vectorName);
128         Kst::Vector* vectorX = static_cast<Kst::Vector*>(object);
129         if (vectorX) {
130           setSelectedVectorX(vectorX);
131         }
132         vectorName = _cfg->value("Input Vector Y").toString();
133         object = _store->retrieveObject(vectorName);
134         Kst::Vector* vectorY = static_cast<Kst::Vector*>(object);
135         if (vectorY) {
136           setSelectedVectorY(vectorY);
137         }
138         QString scalarName = _cfg->value("Input Scalar Number of Bins").toString();
139         object = _store->retrieveObject(scalarName);
140         Kst::Scalar* scalarBins = static_cast<Kst::Scalar*>(object);
141         if (scalarBins) {
142           setSelectedScalarBins(scalarBins);
143         }
144         scalarName = _cfg->value("Input Scalar X Min").toString();
145         object = _store->retrieveObject(scalarName);
146         Kst::Scalar* scalarXMin = static_cast<Kst::Scalar*>(object);
147         if (scalarXMin) {
148           setSelectedScalarXMin(scalarXMin);
149         }
150         scalarName = _cfg->value("Input Scalar X Max").toString();
151         object = _store->retrieveObject(scalarName);
152         Kst::Scalar* scalarXMax = static_cast<Kst::Scalar*>(object);
153         if (scalarXMax) {
154           setSelectedScalarXMax(scalarXMax);
155         }
156         _cfg->endGroup();
157       }
158     }
159 
160   private:
161     Kst::ObjectStore *_store;
162 
163 };
164 
165 
SyncBinSource(Kst::ObjectStore * store)166 SyncBinSource::SyncBinSource(Kst::ObjectStore *store)
167 : Kst::BasicPlugin(store) {
168 }
169 
170 
~SyncBinSource()171 SyncBinSource::~SyncBinSource() {
172 }
173 
174 
_automaticDescriptiveName() const175 QString SyncBinSource::_automaticDescriptiveName() const {
176   return tr("SyncBin Plugin Object");
177 }
178 
179 
change(Kst::DataObjectConfigWidget * configWidget)180 void SyncBinSource::change(Kst::DataObjectConfigWidget *configWidget) {
181   if (ConfigSyncBinPlugin* config = static_cast<ConfigSyncBinPlugin*>(configWidget)) {
182     setInputVector(VECTOR_IN_X, config->selectedVectorX());
183     setInputVector(VECTOR_IN_Y, config->selectedVectorY());
184     setInputScalar(SCALAR_IN_BINS, config->selectedScalarBins());
185     setInputScalar(SCALAR_IN_XMIN, config->selectedScalarXMin());
186     setInputScalar(SCALAR_IN_XMAX, config->selectedScalarXMax());
187   }
188 }
189 
190 
setupOutputs()191 void SyncBinSource::setupOutputs() {
192   setOutputVector(VECTOR_OUT_X_OUT, "");
193   setOutputVector(VECTOR_OUT_Y_OUT, "");
194   setOutputVector(VECTOR_OUT_Y_ERROR, "");
195   setOutputVector(VECTOR_OUT_N, "");
196 }
197 
198 
algorithm()199 bool SyncBinSource::algorithm() {
200   Kst::VectorPtr inputVectorX = _inputVectors[VECTOR_IN_X];
201   Kst::VectorPtr inputVectorY = _inputVectors[VECTOR_IN_Y];
202   Kst::ScalarPtr inputScalarBins = _inputScalars[SCALAR_IN_BINS];
203   Kst::ScalarPtr inputScalarXMin = _inputScalars[SCALAR_IN_XMIN];
204   Kst::ScalarPtr inputScalarXMax = _inputScalars[SCALAR_IN_XMAX];
205 
206   Kst::VectorPtr outputVectorX = _outputVectors[VECTOR_OUT_X_OUT];
207   Kst::VectorPtr outputVectorY = _outputVectors[VECTOR_OUT_Y_OUT];
208   Kst::VectorPtr outputVectorYError = _outputVectors[VECTOR_OUT_Y_ERROR];
209   Kst::VectorPtr outputVectorN = _outputVectors[VECTOR_OUT_N];
210 
211   int nbins = int( inputScalarBins->value() );
212   int n_in;
213   double XMin = inputScalarXMin->value();
214   double XMax = inputScalarXMax->value();
215   double *Xout, *Yout, *Yerr, *N;
216 
217   //Make sure there is at least 1 element in the input vector
218   if (inputVectorX->length() < 1) {
219     _errorString = tr("Error:  Input Vector X invalid size");
220     return false;
221   }
222   if (inputVectorX->length() != inputVectorY->length()) {
223     _errorString = tr("Error:  Input Vector lengths do not match");
224     return false;
225   }
226 
227   if (nbins < 2) {
228     _errorString = tr("Error:  Bins must be at least 2");
229     return false;
230   }
231 
232   //resize the output arrays
233   outputVectorX->resize(nbins, true);
234   outputVectorY->resize(nbins, true);
235   outputVectorYError->resize(nbins, true);
236   outputVectorN->resize(nbins, true);
237 
238   // convenience definitions
239   n_in = int( inputVectorX->length() );
240   const double *Xin = inputVectorX->value();
241   const double *Yin = inputVectorY->value();
242   Xout = outputVectorX->raw_V_ptr();
243   Yout = outputVectorY->raw_V_ptr();
244   Yerr = outputVectorYError->raw_V_ptr();
245   N    = outputVectorN->raw_V_ptr();
246 
247   // set/check XMax and XMin
248   if ( XMax <= XMin ) { // autobin
249     XMax = XMin = Xin[0];
250     for (int i=1; i<n_in; i++ ) {
251       if ( XMax>Xin[i] ) XMax = Xin[i];
252       if ( XMin<Xin[i] ) XMin = Xin[i];
253     }
254     // make sure end points are included.
255     double d = (XMax - XMin)/double(nbins*100.0);
256     XMax+=d;
257     XMin-=d;
258   }
259 
260   if ( XMax == XMin ) { // don't want divide by zero...
261     XMax +=1;
262     XMin -=1;
263   }
264 
265   // Fill Xout and zero Yout and Yerr
266   for ( int i=0; i<nbins; i++ ) {
267     Xout[i] = BINMID( i );
268     Yout[i] = Yerr[i] = 0.0;
269     N[i] = 0.0;
270   }
271 
272   //bin the data
273   int bin, last_bin=-1;
274   int last_N=0;
275   double last_sY=0;
276 
277   for ( int i=0; i<n_in; i++ ) {
278     bin = BIN( Xin[i] );
279     if (bin == last_bin) {
280       last_sY += Yin[i];
281       last_N++;
282     } else { // new bin
283       if (last_N>0) {
284         last_sY/=last_N;
285         if ( (last_bin>=0) && (last_bin<nbins) ) {
286           Yout[last_bin]+=last_sY;
287           Yerr[last_bin]+=last_sY*last_sY;
288           N[last_bin]++;
289         }
290       }
291       last_sY = Yin[i];
292       last_N = 1;
293       last_bin = bin;
294     }
295   }
296   if (last_N>0) {
297     last_sY/=last_N;
298     if ( (last_bin>=0) && (last_bin<nbins) ) {
299       Yout[last_bin]+=last_sY;
300       Yerr[last_bin]+=last_sY*last_sY;
301       N[last_bin]++;
302     }
303   }
304 
305   // normalize the inputScalarBins
306   for ( int i = 0; i<nbins; i++ ) {
307     if ( N[i]>0 ) {
308       Yerr[i] = sqrt( Yerr[i] - Yout[i]*Yout[i]/N[i] )/N[i];
309       Yout[i]/=N[i];
310     }
311   }
312 
313   return true;
314 }
315 
316 
vectorX() const317 Kst::VectorPtr SyncBinSource::vectorX() const {
318   return _inputVectors[VECTOR_IN_X];
319 }
320 
321 
vectorY() const322 Kst::VectorPtr SyncBinSource::vectorY() const {
323   return _inputVectors[VECTOR_IN_Y];
324 }
325 
326 
scalarBins() const327 Kst::ScalarPtr SyncBinSource::scalarBins() const {
328   return _inputScalars[SCALAR_IN_BINS];
329 }
330 
331 
scalarXMin() const332 Kst::ScalarPtr SyncBinSource::scalarXMin() const {
333   return _inputScalars[SCALAR_IN_XMIN];
334 }
335 
336 
scalarXMax() const337 Kst::ScalarPtr SyncBinSource::scalarXMax() const {
338   return _inputScalars[SCALAR_IN_XMAX];
339 }
340 
341 
inputVectorList() const342 QStringList SyncBinSource::inputVectorList() const {
343   QStringList vectors(VECTOR_IN_X);
344   vectors += VECTOR_IN_Y;
345   return vectors;
346 }
347 
348 
inputScalarList() const349 QStringList SyncBinSource::inputScalarList() const {
350   QStringList scalars(SCALAR_IN_BINS);
351   scalars += SCALAR_IN_XMIN;
352   scalars += SCALAR_IN_XMAX;
353   return scalars;
354 }
355 
356 
inputStringList() const357 QStringList SyncBinSource::inputStringList() const {
358   return QStringList( /*STRING_IN*/ );
359 }
360 
361 
outputVectorList() const362 QStringList SyncBinSource::outputVectorList() const {
363   QStringList vectors(VECTOR_OUT_X_OUT);
364   vectors += VECTOR_OUT_Y_OUT;
365   vectors += VECTOR_OUT_Y_ERROR;
366   vectors += VECTOR_OUT_N;
367   return vectors;
368 }
369 
370 
outputScalarList() const371 QStringList SyncBinSource::outputScalarList() const {
372   return QStringList( /*SCALAR_OUT*/ );
373 }
374 
375 
outputStringList() const376 QStringList SyncBinSource::outputStringList() const {
377   return QStringList( /*STRING_OUT*/ );
378 }
379 
380 
saveProperties(QXmlStreamWriter & s)381 void SyncBinSource::saveProperties(QXmlStreamWriter &s) {
382   Q_UNUSED(s);
383 //   s.writeAttribute("value", _configValue);
384 }
385 
386 
pluginName() const387 QString SyncBinPlugin::pluginName() const { return tr("SyncBin"); }
pluginDescription() const388 QString SyncBinPlugin::pluginDescription() const { return tr("Synchronously coadd vector Y into inputScalarBins defined by vector X.  Like a 1D map."); }
389 
390 
create(Kst::ObjectStore * store,Kst::DataObjectConfigWidget * configWidget,bool setupInputsOutputs) const391 Kst::DataObject *SyncBinPlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const {
392 
393   if (ConfigSyncBinPlugin* config = static_cast<ConfigSyncBinPlugin*>(configWidget)) {
394 
395     SyncBinSource* object = store->createObject<SyncBinSource>();
396 
397     if (setupInputsOutputs) {
398       object->setInputScalar(SCALAR_IN_BINS, config->selectedScalarBins());
399       object->setInputScalar(SCALAR_IN_XMIN, config->selectedScalarXMin());
400       object->setInputScalar(SCALAR_IN_XMAX, config->selectedScalarXMax());
401       object->setupOutputs();
402       object->setInputVector(VECTOR_IN_X, config->selectedVectorX());
403       object->setInputVector(VECTOR_IN_Y, config->selectedVectorY());
404     }
405 
406     object->setPluginName(pluginName());
407 
408     object->writeLock();
409     object->registerChange();
410     object->unlock();
411 
412     return object;
413   }
414   return 0;
415 }
416 
417 
configWidget(QSettings * settingsObject) const418 Kst::DataObjectConfigWidget *SyncBinPlugin::configWidget(QSettings *settingsObject) const {
419   ConfigSyncBinPlugin *widget = new ConfigSyncBinPlugin(settingsObject);
420   return widget;
421 }
422 
423 #ifndef QT5
424 Q_EXPORT_PLUGIN2(kstplugin_BinPlugin, SyncBinPlugin)
425 #endif
426 
427 // vim: ts=2 sw=2 et
428