File indexing completed on 2025-01-05 04:12:50

0001 /***************************************************************************
0002  *                                                                         *
0003  *   copyright : (C) 2007 The University of Toronto                        *
0004  *                   netterfield@astro.utoronto.ca                         *
0005  *   copyright : (C) 2005  University of British Columbia                  *
0006  *                   dscott@phas.ubc.ca                                    *
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 
0016 #include "crosscorrelation.h"
0017 #include "objectstore.h"
0018 #include "ui_crosscorrelationconfig.h"
0019 
0020 #include <gsl/gsl_fft_real.h>
0021 #include <gsl/gsl_fft_halfcomplex.h>
0022 
0023 
0024 static const QString& VECTOR_IN_ONE = "Vector One In";
0025 static const QString& VECTOR_IN_TWO = "Vector Two In";
0026 static const QString& VECTOR_OUT_STEP = "Offset";
0027 static const QString& VECTOR_OUT_CORRELATED = "C";
0028 
0029 class ConfigCrossCorrelationPlugin : public Kst::DataObjectConfigWidget, public Ui_CrossCorrelationConfig {
0030   public:
0031     ConfigCrossCorrelationPlugin(QSettings* cfg) : DataObjectConfigWidget(cfg), Ui_CrossCorrelationConfig() {
0032       _store = 0;
0033       setupUi(this);
0034     }
0035 
0036     ~ConfigCrossCorrelationPlugin() {}
0037 
0038     void setObjectStore(Kst::ObjectStore* store) { 
0039       _store = store; 
0040       _vectorOne->setObjectStore(store); 
0041       _vectorTwo->setObjectStore(store); 
0042     }
0043 
0044     void setupSlots(QWidget* dialog) {
0045       if (dialog) {
0046         connect(_vectorOne, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
0047         connect(_vectorTwo, SIGNAL(selectionChanged(QString)), dialog, SIGNAL(modified()));
0048       }
0049     }
0050 
0051     Kst::VectorPtr selectedVectorOne() { return _vectorOne->selectedVector(); };
0052     void setSelectedVectorOne(Kst::VectorPtr vector) { return _vectorOne->setSelectedVector(vector); };
0053 
0054     Kst::VectorPtr selectedVectorTwo() { return _vectorTwo->selectedVector(); };
0055     void setSelectedVectorTwo(Kst::VectorPtr vector) { return _vectorTwo->setSelectedVector(vector); };
0056 
0057     virtual void setupFromObject(Kst::Object* dataObject) {
0058       if (CrossCorrelationSource* source = static_cast<CrossCorrelationSource*>(dataObject)) {
0059         setSelectedVectorOne(source->vectorOne());
0060         setSelectedVectorTwo(source->vectorTwo());
0061       }
0062     }
0063 
0064     virtual bool configurePropertiesFromXml(Kst::ObjectStore *store, QXmlStreamAttributes& attrs) {
0065       Q_UNUSED(store);
0066       Q_UNUSED(attrs);
0067 
0068       bool validTag = true;
0069 
0070 //       QStringRef av;
0071 //       av = attrs.value("value");
0072 //       if (!av.isNull()) {
0073 //         _configValue = QVariant(av.toString()).toBool();
0074 //       }
0075 
0076       return validTag;
0077     }
0078 
0079   public slots:
0080     virtual void save() {
0081       if (_cfg) {
0082         _cfg->beginGroup("Cross Correlation DataObject Plugin");
0083         _cfg->setValue("Input Vector One", _vectorOne->selectedVector()->Name());
0084         _cfg->setValue("Input Vector Two", _vectorTwo->selectedVector()->Name());
0085         _cfg->endGroup();
0086       }
0087     }
0088 
0089     virtual void load() {
0090       if (_cfg && _store) {
0091         _cfg->beginGroup("Cross Correlation DataObject Plugin");
0092         QString vectorName = _cfg->value("Input Vector One").toString();
0093         Kst::Object* object = _store->retrieveObject(vectorName);
0094         Kst::Vector* vector = static_cast<Kst::Vector*>(object);
0095         if (vector) {
0096           setSelectedVectorOne(vector);
0097         }
0098         vectorName = _cfg->value("Input Vector Two").toString();
0099         Kst::Object* object2 = _store->retrieveObject(vectorName);
0100         Kst::Vector* vector2 = static_cast<Kst::Vector*>(object2);
0101         if (vector2) {
0102           setSelectedVectorTwo(vector2);
0103         }
0104         _cfg->endGroup();
0105       }
0106     }
0107 
0108   private:
0109     Kst::ObjectStore *_store;
0110 
0111 };
0112 
0113 
0114 CrossCorrelationSource::CrossCorrelationSource(Kst::ObjectStore *store)
0115 : Kst::BasicPlugin(store) {
0116 }
0117 
0118 
0119 CrossCorrelationSource::~CrossCorrelationSource() {
0120 }
0121 
0122 
0123 QString CrossCorrelationSource::_automaticDescriptiveName() const {
0124   return tr("Cross Correlation");
0125 }
0126 
0127 
0128 void CrossCorrelationSource::change(Kst::DataObjectConfigWidget *configWidget) {
0129   if (ConfigCrossCorrelationPlugin* config = static_cast<ConfigCrossCorrelationPlugin*>(configWidget)) {
0130     setInputVector(VECTOR_IN_ONE, config->selectedVectorOne());
0131     setInputVector(VECTOR_IN_TWO, config->selectedVectorTwo());
0132   }
0133 }
0134 
0135 
0136 void CrossCorrelationSource::setupOutputs() {
0137   setOutputVector(VECTOR_OUT_STEP, "");
0138   setOutputVector(VECTOR_OUT_CORRELATED, "");
0139 }
0140 
0141 
0142 bool CrossCorrelationSource::algorithm() {
0143   Kst::VectorPtr inputVectorOne = _inputVectors[VECTOR_IN_ONE];
0144   Kst::VectorPtr inputVectorTwo = _inputVectors[VECTOR_IN_TWO];
0145   Kst::VectorPtr outputVectorStep = _outputVectors[VECTOR_OUT_STEP];
0146   Kst::VectorPtr outputVectorCorrelated = _outputVectors[VECTOR_OUT_CORRELATED];
0147 
0148   if (inputVectorOne->length() <= 0 || inputVectorTwo->length() <= 0 || inputVectorOne->length() != inputVectorTwo->length()) {
0149     _errorString = tr("Error:  Input Vectors - invalid size");
0150     return false;
0151   }
0152 
0153   double* pdArrayOne;
0154   double* pdArrayTwo;
0155   double* pdResult[2];
0156   double  dReal;
0157   double  dImag;
0158 
0159   int iLength;
0160   int iLengthNew;
0161 
0162   bool bReturn = false;
0163 
0164   //
0165   // zero-pad the array...
0166   //
0167   iLength  = inputVectorOne->length();
0168   iLength *= 2;
0169 
0170   outputVectorStep->resize(inputVectorOne->length(), false);
0171   outputVectorCorrelated->resize(inputVectorTwo->length(), false);
0172 
0173   //
0174   // round iLength up to the nearest power of two...
0175   //
0176   iLengthNew = 64;
0177   while( iLengthNew < iLength && iLengthNew > 0) {
0178     iLengthNew *= 2;
0179   }
0180   iLength = iLengthNew;
0181 
0182   if (iLength <= 0) {
0183     _errorString = tr("Error:  Invalid Input length calculated");
0184     return false;
0185   }
0186 
0187   pdArrayOne = new double[iLength];
0188   pdArrayTwo = new double[iLength];
0189   if (pdArrayOne != NULL && pdArrayTwo != NULL) {
0190     //
0191     // zero-pad the two arrays...
0192     //
0193     memset( pdArrayOne, 0, iLength * sizeof( double ) );
0194     memcpy( pdArrayOne, inputVectorOne->value(), inputVectorOne->length() * sizeof( double ) );
0195 
0196     memset( pdArrayTwo, 0, iLength * sizeof( double ) );
0197     memcpy( pdArrayTwo, inputVectorTwo->value(), inputVectorTwo->length() * sizeof( double ) );
0198 
0199     //
0200     // calculate the FFTs of the two functions...
0201     //
0202     if (gsl_fft_real_radix2_transform( pdArrayOne, 1, iLength ) == 0) {
0203       if (gsl_fft_real_radix2_transform( pdArrayTwo, 1, iLength ) == 0) {
0204         //
0205         // multiply one FFT by the complex conjugate of the other...
0206         //
0207         for (int i=0; i<iLength/2; i++) {
0208           if (i==0 || i==(iLength/2)-1) {
0209             pdArrayOne[i] = pdArrayOne[i] * pdArrayTwo[i];
0210           } else {
0211             dReal = pdArrayOne[i] * pdArrayTwo[i] + pdArrayOne[iLength-i] * pdArrayTwo[iLength-i];
0212             dImag = pdArrayOne[i] * pdArrayTwo[iLength-i] - pdArrayOne[iLength-i] * pdArrayTwo[i];
0213 
0214             pdArrayOne[i] = dReal;
0215             pdArrayOne[iLength-i] = dImag;
0216           }
0217         }
0218 
0219         //
0220         // do the inverse FFT...
0221         //
0222         if (gsl_fft_halfcomplex_radix2_inverse( pdArrayOne, 1, iLength ) == 0) {
0223           pdResult[0] = outputVectorStep->raw_V_ptr();
0224           pdResult[1] = outputVectorCorrelated->raw_V_ptr();
0225 
0226           if (pdResult[0] != NULL && pdResult[1] != NULL) {
0227             for (int i = 0; i < inputVectorOne->length(); ++i) {
0228               outputVectorStep->raw_V_ptr()[i] = pdResult[0][i];
0229             }
0230             for (int i = 0; i < inputVectorTwo->length(); ++i) {
0231               outputVectorCorrelated->raw_V_ptr()[i] = pdResult[1][i];
0232             }
0233 
0234             for (int i = 0; i < inputVectorOne->length(); i++) {
0235                 outputVectorStep->raw_V_ptr()[i] = (double)( i - ( inputVectorOne->length() / 2 ) );
0236             }
0237 
0238             memcpy( &(outputVectorCorrelated->raw_V_ptr()[inputVectorOne->length() / 2]),
0239                     &(pdArrayOne[0]),
0240                     ( ( inputVectorOne->length() + 1 ) / 2 ) * sizeof( double ) );
0241 
0242             memcpy( &(outputVectorCorrelated->raw_V_ptr()[0]),
0243                     &(pdArrayOne[iLength - (inputVectorOne->length() / 2)]),
0244                     ( inputVectorOne->length() / 2 ) * sizeof( double ) );
0245 
0246             bReturn = true;
0247           }
0248         }
0249       }
0250     }
0251   }
0252   delete[] pdArrayOne;
0253   delete[] pdArrayTwo;
0254 
0255   return bReturn;
0256 }
0257 
0258 
0259 Kst::VectorPtr CrossCorrelationSource::vectorOne() const {
0260   return _inputVectors[VECTOR_IN_ONE];
0261 }
0262 
0263 
0264 Kst::VectorPtr CrossCorrelationSource::vectorTwo() const {
0265   return _inputVectors[VECTOR_IN_TWO];
0266 }
0267 
0268 
0269 QStringList CrossCorrelationSource::inputVectorList() const {
0270   QStringList vectors(VECTOR_IN_ONE);
0271   vectors += VECTOR_IN_TWO;
0272   return vectors;
0273 }
0274 
0275 
0276 QStringList CrossCorrelationSource::inputScalarList() const {
0277   return QStringList( /*SCALAR_IN*/ );
0278 }
0279 
0280 
0281 QStringList CrossCorrelationSource::inputStringList() const {
0282   return QStringList( /*STRING_IN*/ );
0283 }
0284 
0285 
0286 QStringList CrossCorrelationSource::outputVectorList() const {
0287   QStringList vectors(VECTOR_OUT_CORRELATED);
0288   vectors += VECTOR_OUT_STEP;
0289   return vectors;
0290 }
0291 
0292 
0293 QStringList CrossCorrelationSource::outputScalarList() const {
0294   return QStringList( /*SCALAR_OUT*/ );
0295 }
0296 
0297 
0298 QStringList CrossCorrelationSource::outputStringList() const {
0299   return QStringList( /*STRING_OUT*/ );
0300 }
0301 
0302 
0303 void CrossCorrelationSource::saveProperties(QXmlStreamWriter &s) {
0304   Q_UNUSED(s);
0305 //   s.writeAttribute("value", _configValue);
0306 }
0307 
0308 
0309 QString CrossCorrelationPlugin::pluginName() const { return tr("Cross Correlation"); }
0310 QString CrossCorrelationPlugin::pluginDescription() const { return tr("Generates the correlation of one vector with another."); }
0311 
0312 
0313 Kst::DataObject *CrossCorrelationPlugin::create(Kst::ObjectStore *store, Kst::DataObjectConfigWidget *configWidget, bool setupInputsOutputs) const {
0314 
0315   if (ConfigCrossCorrelationPlugin* config = static_cast<ConfigCrossCorrelationPlugin*>(configWidget)) {
0316 
0317     CrossCorrelationSource* object = store->createObject<CrossCorrelationSource>();
0318 
0319     if (setupInputsOutputs) {
0320       object->setupOutputs();
0321       object->setInputVector(VECTOR_IN_ONE, config->selectedVectorOne());
0322       object->setInputVector(VECTOR_IN_TWO, config->selectedVectorTwo());
0323     }
0324 
0325     object->setPluginName(pluginName());
0326 
0327     object->writeLock();
0328     object->registerChange();
0329     object->unlock();
0330 
0331     return object;
0332   }
0333   return 0;
0334 }
0335 
0336 
0337 Kst::DataObjectConfigWidget *CrossCorrelationPlugin::configWidget(QSettings *settingsObject) const {
0338   ConfigCrossCorrelationPlugin *widget = new ConfigCrossCorrelationPlugin(settingsObject);
0339   return widget;
0340 }
0341 
0342 #ifndef QT5
0343 Q_EXPORT_PLUGIN2(kstplugin_ConvolvePlugin, CrossCorrelationPlugin)
0344 #endif
0345 
0346 // vim: ts=2 sw=2 et